]> git.xonotic.org Git - xonotic/gmqcc.git/blob - intrin.cpp
s/NULL/nullptr/
[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 = nullptr;
8     ast_function *func  = nullptr;
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 nullptr
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 = nullptr;
44     ast_function *func  = intrin_value(intrin, &value, nullptr, 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     = nullptr;
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     func->blocks.push_back(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 = nullptr;
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     func->blocks.push_back(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  = nullptr;
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     func->blocks.push_back(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         = nullptr;
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     func->blocks.push_back(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  = nullptr;
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     func->blocks.push_back(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    = nullptr;
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     func->blocks.push_back(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    = nullptr;
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     func->blocks.push_back(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   = nullptr;
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     func->blocks.push_back(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 = nullptr;
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             nullptr,
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     func->blocks.push_back(body);
513     intrin_reg(intrin, value, func);
514     return (ast_expression*)value;
515 }
516
517 static ast_expression *intrin_exp2(intrin_t *intrin) {
518     /*
519      * float exp2(float x) {
520      *     return pow(2, x);
521      * }
522      */
523     ast_value    *value     = nullptr;
524     ast_call     *callpow   = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp2"));
525     ast_value    *arg1      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
526     ast_block    *body      = ast_block_new(intrin_ctx(intrin));
527     ast_function *func      = intrin_value(intrin, &value, "exp2", TYPE_FLOAT);
528
529     value->expression.params.push_back(arg1);
530
531     callpow->params.push_back((ast_expression*)intrin->fold->imm_float[3]);
532     callpow->params.push_back((ast_expression*)arg1);
533
534     /* return <callpow> */
535     body->exprs.push_back(
536         (ast_expression*)ast_return_new(
537             intrin_ctx(intrin),
538             (ast_expression*)callpow
539         )
540     );
541
542     func->blocks.push_back(body);
543     intrin_reg(intrin, value, func);
544     return (ast_expression*)value;
545 }
546
547 static ast_expression *intrin_expm1(intrin_t *intrin) {
548     /*
549      * float expm1(float x) {
550      *     return exp(x) - 1;
551      * }
552      */
553     ast_value    *value    = nullptr;
554     ast_call     *callexp  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "exp", "expm1"));
555     ast_value    *x        = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
556     ast_block    *body     = ast_block_new(intrin_ctx(intrin));
557     ast_function *func     = intrin_value(intrin, &value, "expm1", TYPE_FLOAT);
558
559     value->expression.params.push_back(x);
560
561     /* <callexp> = exp(x); */
562     callexp->params.push_back((ast_expression*)x);
563
564     /* return <callexp> - 1; */
565     body->exprs.push_back(
566         (ast_expression*)ast_return_new(
567             intrin_ctx(intrin),
568             (ast_expression*)ast_binary_new(
569                 intrin_ctx(intrin),
570                 INSTR_SUB_F,
571                 (ast_expression*)callexp,
572                 (ast_expression*)intrin->fold->imm_float[1]
573             )
574         )
575     );
576
577     func->blocks.push_back(body);
578     intrin_reg(intrin, value, func);
579     return (ast_expression*)value;
580 }
581
582 static ast_expression *intrin_pow(intrin_t *intrin) {
583     /*
584      *
585      * float pow(float base, float exp) {
586      *     float result;
587      *     float low;
588      *     float high;
589      *     float mid;
590      *     float square;
591      *     float accumulate;
592      *
593      *     if (exp == 0.0)
594      *         return 1;
595      *     if (exp == 1.0)
596      *         return base;
597      *     if (exp < 0)
598      *         return 1.0 / pow(base, -exp);
599      *     if (exp >= 1) {
600      *         result = pow(base, exp / 2);
601      *         return result * result;
602      *     }
603      *
604      *     low        = 0.0f;
605      *     high       = 1.0f;
606      *     square     = sqrt(base);
607      *     accumulate = square;
608      *     mid        = high / 2.0f
609      *
610      *     while (fabs(mid - exp) > QC_POW_EPSILON) {
611      *         square = sqrt(square);
612      *         if (mid < exp) {
613      *             low         = mid;
614      *             accumulate *= square;
615      *         } else {
616      *             high        = mid;
617      *             accumulate *= (1.0f / square);
618      *         }
619      *         mid = (low + high) / 2;
620      *     }
621      *     return accumulate;
622      * }
623      */
624     ast_value    *value = nullptr;
625     ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
626
627     /* prepare some calls for later */
628     ast_call *callpow1  = ast_call_new(intrin_ctx(intrin), (ast_expression*)value);                  /* for pow(base, -exp)    */
629     ast_call *callpow2  = ast_call_new(intrin_ctx(intrin), (ast_expression*)value);                  /* for pow(vase, exp / 2) */
630     ast_call *callsqrt1 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(base)         */
631     ast_call *callsqrt2 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(square)       */
632     ast_call *callfabs  = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "fabs", "pow")); /* for fabs(mid - exp)    */
633
634     /* prepare some blocks for later */
635     ast_block *expgt1       = ast_block_new(intrin_ctx(intrin));
636     ast_block *midltexp     = ast_block_new(intrin_ctx(intrin));
637     ast_block *midltexpelse = ast_block_new(intrin_ctx(intrin));
638     ast_block *whileblock   = ast_block_new(intrin_ctx(intrin));
639
640     /* float pow(float base, float exp) */
641     ast_value    *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
642     ast_value    *exp  = ast_value_new(intrin_ctx(intrin), "exp",  TYPE_FLOAT);
643     /* { */
644     ast_block    *body = ast_block_new(intrin_ctx(intrin));
645
646     /*
647      * float result;
648      * float low;
649      * float high;
650      * float square;
651      * float accumulate;
652      * float mid;
653      */
654     ast_value *result     = ast_value_new(intrin_ctx(intrin), "result",     TYPE_FLOAT);
655     ast_value *low        = ast_value_new(intrin_ctx(intrin), "low",        TYPE_FLOAT);
656     ast_value *high       = ast_value_new(intrin_ctx(intrin), "high",       TYPE_FLOAT);
657     ast_value *square     = ast_value_new(intrin_ctx(intrin), "square",     TYPE_FLOAT);
658     ast_value *accumulate = ast_value_new(intrin_ctx(intrin), "accumulate", TYPE_FLOAT);
659     ast_value *mid        = ast_value_new(intrin_ctx(intrin), "mid",        TYPE_FLOAT);
660     body->locals.push_back(result);
661     body->locals.push_back(low);
662     body->locals.push_back(high);
663     body->locals.push_back(square);
664     body->locals.push_back(accumulate);
665     body->locals.push_back(mid);
666
667     value->expression.params.push_back(base);
668     value->expression.params.push_back(exp);
669
670     /*
671      * if (exp == 0.0)
672      *     return 1;
673      */
674     body->exprs.push_back(
675         (ast_expression*)ast_ifthen_new(
676             intrin_ctx(intrin),
677             (ast_expression*)ast_binary_new(
678                 intrin_ctx(intrin),
679                 INSTR_EQ_F,
680                 (ast_expression*)exp,
681                 (ast_expression*)intrin->fold->imm_float[0]
682             ),
683             (ast_expression*)ast_return_new(
684                 intrin_ctx(intrin),
685                 (ast_expression*)intrin->fold->imm_float[1]
686             ),
687             nullptr
688         )
689     );
690
691     /*
692      * if (exp == 1.0)
693      *     return base;
694      */
695     body->exprs.push_back(
696         (ast_expression*)ast_ifthen_new(
697             intrin_ctx(intrin),
698             (ast_expression*)ast_binary_new(
699                 intrin_ctx(intrin),
700                 INSTR_EQ_F,
701                 (ast_expression*)exp,
702                 (ast_expression*)intrin->fold->imm_float[1]
703             ),
704             (ast_expression*)ast_return_new(
705                 intrin_ctx(intrin),
706                 (ast_expression*)base
707             ),
708             nullptr
709         )
710     );
711
712     /* <callpow1> = pow(base, -exp) */
713     callpow1->params.push_back((ast_expression*)base);
714     callpow1->params.push_back(
715         (ast_expression*)ast_unary_new(
716             intrin_ctx(intrin),
717             VINSTR_NEG_F,
718             (ast_expression*)exp
719         )
720     );
721
722     /*
723      * if (exp < 0)
724      *     return 1.0 / <callpow1>;
725      */
726     body->exprs.push_back(
727         (ast_expression*)ast_ifthen_new(
728             intrin_ctx(intrin),
729             (ast_expression*)ast_binary_new(
730                 intrin_ctx(intrin),
731                 INSTR_LT,
732                 (ast_expression*)exp,
733                 (ast_expression*)intrin->fold->imm_float[0]
734             ),
735             (ast_expression*)ast_return_new(
736                 intrin_ctx(intrin),
737                 (ast_expression*)ast_binary_new(
738                     intrin_ctx(intrin),
739                     INSTR_DIV_F,
740                     (ast_expression*)intrin->fold->imm_float[1],
741                     (ast_expression*)callpow1
742                 )
743             ),
744             nullptr
745         )
746     );
747
748     /* <callpow2> = pow(base, exp / 2) */
749     callpow2->params.push_back((ast_expression*)base);
750     callpow2->params.push_back(
751         (ast_expression*)ast_binary_new(
752             intrin_ctx(intrin),
753             INSTR_DIV_F,
754             (ast_expression*)exp,
755             (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
756         )
757     );
758
759     /*
760      * <expgt1> = {
761      *     result = <callpow2>;
762      *     return result * result;
763      * }
764      */
765     expgt1->exprs.push_back(
766         (ast_expression*)ast_store_new(
767             intrin_ctx(intrin),
768             INSTR_STORE_F,
769             (ast_expression*)result,
770             (ast_expression*)callpow2
771         )
772     );
773     expgt1->exprs.push_back(
774         (ast_expression*)ast_return_new(
775             intrin_ctx(intrin),
776             (ast_expression*)ast_binary_new(
777                 intrin_ctx(intrin),
778                 INSTR_MUL_F,
779                 (ast_expression*)result,
780                 (ast_expression*)result
781             )
782         )
783     );
784
785     /*
786      * if (exp >= 1) {
787      *     <expgt1>
788      * }
789      */
790     body->exprs.push_back(
791         (ast_expression*)ast_ifthen_new(
792             intrin_ctx(intrin),
793             (ast_expression*)ast_binary_new(
794                 intrin_ctx(intrin),
795                 INSTR_GE,
796                 (ast_expression*)exp,
797                 (ast_expression*)intrin->fold->imm_float[1]
798             ),
799             (ast_expression*)expgt1,
800             nullptr
801         )
802     );
803
804     /*
805      * <callsqrt1> = sqrt(base)
806      */
807     callsqrt1->params.push_back((ast_expression*)base);
808
809     /*
810      * low        = 0.0f;
811      * high       = 1.0f;
812      * square     = sqrt(base);
813      * accumulate = square;
814      * mid        = high / 2.0f;
815      */
816     body->exprs.push_back(
817         (ast_expression*)ast_store_new(intrin_ctx(intrin),
818             INSTR_STORE_F,
819             (ast_expression*)low,
820             (ast_expression*)intrin->fold->imm_float[0]
821         )
822     );
823     body->exprs.push_back(
824         (ast_expression*)ast_store_new(
825             intrin_ctx(intrin),
826             INSTR_STORE_F,
827             (ast_expression*)high,
828             (ast_expression*)intrin->fold->imm_float[1]
829         )
830     );
831
832     body->exprs.push_back(
833         (ast_expression*)ast_store_new(
834             intrin_ctx(intrin),
835             INSTR_STORE_F,
836             (ast_expression*)square,
837             (ast_expression*)callsqrt1
838         )
839     );
840
841     body->exprs.push_back(
842         (ast_expression*)ast_store_new(
843             intrin_ctx(intrin),
844             INSTR_STORE_F,
845             (ast_expression*)accumulate,
846             (ast_expression*)square
847         )
848     );
849     body->exprs.push_back(
850         (ast_expression*)ast_store_new(
851             intrin_ctx(intrin),
852             INSTR_STORE_F,
853             (ast_expression*)mid,
854             (ast_expression*)ast_binary_new(
855                 intrin_ctx(intrin),
856                 INSTR_DIV_F,
857                 (ast_expression*)high,
858                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
859             )
860         )
861     );
862
863     /*
864      * <midltexp> = {
865      *     low         = mid;
866      *     accumulate *= square;
867      * }
868      */
869     midltexp->exprs.push_back(
870         (ast_expression*)ast_store_new(
871             intrin_ctx(intrin),
872             INSTR_STORE_F,
873             (ast_expression*)low,
874             (ast_expression*)mid
875         )
876     );
877     midltexp->exprs.push_back(
878         (ast_expression*)ast_binstore_new(
879             intrin_ctx(intrin),
880             INSTR_STORE_F,
881             INSTR_MUL_F,
882             (ast_expression*)accumulate,
883             (ast_expression*)square
884         )
885     );
886
887     /*
888      * <midltexpelse> = {
889      *     high        = mid;
890      *     accumulate *= (1.0 / square);
891      * }
892      */
893     midltexpelse->exprs.push_back(
894         (ast_expression*)ast_store_new(
895             intrin_ctx(intrin),
896             INSTR_STORE_F,
897             (ast_expression*)high,
898             (ast_expression*)mid
899         )
900     );
901     midltexpelse->exprs.push_back(
902         (ast_expression*)ast_binstore_new(
903             intrin_ctx(intrin),
904             INSTR_STORE_F,
905             INSTR_MUL_F,
906             (ast_expression*)accumulate,
907             (ast_expression*)ast_binary_new(
908                 intrin_ctx(intrin),
909                 INSTR_DIV_F,
910                 (ast_expression*)intrin->fold->imm_float[1],
911                 (ast_expression*)square
912             )
913         )
914     );
915
916     /*
917      * <callsqrt2> = sqrt(square)
918      */
919     callsqrt2->params.push_back((ast_expression*)square);
920
921     /*
922      * <whileblock> = {
923      *     square = <callsqrt2>;
924      *     if (mid < exp)
925      *          <midltexp>;
926      *     else
927      *          <midltexpelse>;
928      *
929      *     mid = (low + high) / 2;
930      * }
931      */
932     whileblock->exprs.push_back(
933         (ast_expression*)ast_store_new(
934             intrin_ctx(intrin),
935             INSTR_STORE_F,
936             (ast_expression*)square,
937             (ast_expression*)callsqrt2
938         )
939     );
940     whileblock->exprs.push_back(
941         (ast_expression*)ast_ifthen_new(
942             intrin_ctx(intrin),
943             (ast_expression*)ast_binary_new(
944                 intrin_ctx(intrin),
945                 INSTR_LT,
946                 (ast_expression*)mid,
947                 (ast_expression*)exp
948             ),
949             (ast_expression*)midltexp,
950             (ast_expression*)midltexpelse
951         )
952     );
953     whileblock->exprs.push_back(
954         (ast_expression*)ast_store_new(
955             intrin_ctx(intrin),
956             INSTR_STORE_F,
957             (ast_expression*)mid,
958             (ast_expression*)ast_binary_new(
959                 intrin_ctx(intrin),
960                 INSTR_DIV_F,
961                 (ast_expression*)ast_binary_new(
962                     intrin_ctx(intrin),
963                     INSTR_ADD_F,
964                     (ast_expression*)low,
965                     (ast_expression*)high
966                 ),
967                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
968             )
969         )
970     );
971
972     /*
973      * <callabs> = fabs(mid - exp)
974      */
975     callfabs->params.push_back(
976         (ast_expression*)ast_binary_new(
977             intrin_ctx(intrin),
978             INSTR_SUB_F,
979             (ast_expression*)mid,
980             (ast_expression*)exp
981         )
982     );
983
984     /*
985      * while (<callfabs>  > epsilon)
986      *     <whileblock>
987      */
988     body->exprs.push_back(
989         (ast_expression*)ast_loop_new(
990             intrin_ctx(intrin),
991             /* init */
992             nullptr,
993             /* pre condition */
994             (ast_expression*)ast_binary_new(
995                 intrin_ctx(intrin),
996                 INSTR_GT,
997                 (ast_expression*)callfabs,
998                 (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON, false)
999             ),
1000             /* pre not */
1001             false,
1002             /* post condition */
1003             nullptr,
1004             /* post not */
1005             false,
1006             /* increment expression */
1007             nullptr,
1008             /* code block */
1009             (ast_expression*)whileblock
1010         )
1011     );
1012
1013     /* return accumulate */
1014     body->exprs.push_back(
1015         (ast_expression*)ast_return_new(
1016             intrin_ctx(intrin),
1017             (ast_expression*)accumulate
1018         )
1019     );
1020
1021     /* } */
1022     func->blocks.push_back(body);
1023     intrin_reg(intrin, value, func);
1024     return (ast_expression*)value;
1025 }
1026
1027 static ast_expression *intrin_mod(intrin_t *intrin) {
1028     /*
1029      * float mod(float a, float b) {
1030      *     float div = a / b;
1031      *     float sign = (div < 0.0f) ? -1 : 1;
1032      *     return a - b * sign * floor(sign * div);
1033      * }
1034      */
1035     ast_value    *value = nullptr;
1036     ast_call     *call  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "mod"));
1037     ast_value    *a     = ast_value_new(intrin_ctx(intrin), "a",    TYPE_FLOAT);
1038     ast_value    *b     = ast_value_new(intrin_ctx(intrin), "b",    TYPE_FLOAT);
1039     ast_value    *div   = ast_value_new(intrin_ctx(intrin), "div",  TYPE_FLOAT);
1040     ast_value    *sign  = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
1041     ast_block    *body  = ast_block_new(intrin_ctx(intrin));
1042     ast_function *func  = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
1043
1044     value->expression.params.push_back(a);
1045     value->expression.params.push_back(b);
1046
1047     body->locals.push_back(div);
1048     body->locals.push_back(sign);
1049
1050     /* div = a / b; */
1051     body->exprs.push_back(
1052         (ast_expression*)ast_store_new(
1053             intrin_ctx(intrin),
1054             INSTR_STORE_F,
1055             (ast_expression*)div,
1056             (ast_expression*)ast_binary_new(
1057                 intrin_ctx(intrin),
1058                 INSTR_DIV_F,
1059                 (ast_expression*)a,
1060                 (ast_expression*)b
1061             )
1062         )
1063     );
1064
1065     /* sign = (div < 0.0f) ? -1 : 1; */
1066     body->exprs.push_back(
1067         (ast_expression*)ast_store_new(
1068             intrin_ctx(intrin),
1069             INSTR_STORE_F,
1070             (ast_expression*)sign,
1071             (ast_expression*)ast_ternary_new(
1072                 intrin_ctx(intrin),
1073                 (ast_expression*)ast_binary_new(
1074                     intrin_ctx(intrin),
1075                     INSTR_LT,
1076                     (ast_expression*)div,
1077                     (ast_expression*)intrin->fold->imm_float[0]
1078                 ),
1079                 (ast_expression*)intrin->fold->imm_float[2],
1080                 (ast_expression*)intrin->fold->imm_float[1]
1081             )
1082         )
1083     );
1084
1085     /* floor(sign * div) */
1086     call->params.push_back(
1087         (ast_expression*)ast_binary_new(
1088             intrin_ctx(intrin),
1089             INSTR_MUL_F,
1090             (ast_expression*)sign,
1091             (ast_expression*)div
1092         )
1093     );
1094
1095     /* return a - b * sign * <call> */
1096     body->exprs.push_back(
1097         (ast_expression*)ast_return_new(
1098             intrin_ctx(intrin),
1099             (ast_expression*)ast_binary_new(
1100                 intrin_ctx(intrin),
1101                 INSTR_SUB_F,
1102                 (ast_expression*)a,
1103                 (ast_expression*)ast_binary_new(
1104                     intrin_ctx(intrin),
1105                     INSTR_MUL_F,
1106                     (ast_expression*)b,
1107                     (ast_expression*)ast_binary_new(
1108                         intrin_ctx(intrin),
1109                         INSTR_MUL_F,
1110                         (ast_expression*)sign,
1111                         (ast_expression*)call
1112                     )
1113                 )
1114             )
1115         )
1116     );
1117
1118     func->blocks.push_back(body);
1119     intrin_reg(intrin, value, func);
1120     return (ast_expression*)value;
1121 }
1122
1123 static ast_expression *intrin_fabs(intrin_t *intrin) {
1124     /*
1125      * float fabs(float x) {
1126      *     return x < 0 ? -x : x;
1127      * }
1128      */
1129     ast_value    *value  = nullptr;
1130     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1131     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1132     ast_function *func   = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
1133
1134     body->exprs.push_back(
1135         (ast_expression*)ast_return_new(
1136             intrin_ctx(intrin),
1137             (ast_expression*)ast_ternary_new(
1138                 intrin_ctx(intrin),
1139                 (ast_expression*)ast_binary_new(
1140                     intrin_ctx(intrin),
1141                     INSTR_LE,
1142                     (ast_expression*)arg1,
1143                     (ast_expression*)intrin->fold->imm_float[0]
1144                 ),
1145                 (ast_expression*)ast_unary_new(
1146                     intrin_ctx(intrin),
1147                     VINSTR_NEG_F,
1148                     (ast_expression*)arg1
1149                 ),
1150                 (ast_expression*)arg1
1151             )
1152         )
1153     );
1154
1155     value->expression.params.push_back(arg1);
1156
1157     func->blocks.push_back(body);
1158     intrin_reg(intrin, value, func);
1159     return (ast_expression*)value;
1160 }
1161
1162 static ast_expression *intrin_epsilon(intrin_t *intrin) {
1163     /*
1164      * float epsilon(void) {
1165      *     float eps = 1.0f;
1166      *     do { eps /= 2.0f; } while ((1.0f + (eps / 2.0f)) != 1.0f);
1167      *     return eps;
1168      * }
1169      */
1170     ast_value    *value  = nullptr;
1171     ast_value    *eps    = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
1172     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1173     ast_function *func   = intrin_value(intrin, &value, "epsilon", TYPE_FLOAT);
1174
1175     body->locals.push_back(eps);
1176
1177     /* eps = 1.0f; */
1178     body->exprs.push_back(
1179         (ast_expression*)ast_store_new(
1180             intrin_ctx(intrin),
1181             INSTR_STORE_F,
1182             (ast_expression*)eps,
1183             (ast_expression*)intrin->fold->imm_float[0]
1184         )
1185     );
1186
1187     body->exprs.push_back(
1188         (ast_expression*)ast_loop_new(
1189             intrin_ctx(intrin),
1190             nullptr,
1191             nullptr,
1192             false,
1193             (ast_expression*)ast_binary_new(
1194                 intrin_ctx(intrin),
1195                 INSTR_NE_F,
1196                 (ast_expression*)ast_binary_new(
1197                     intrin_ctx(intrin),
1198                     INSTR_ADD_F,
1199                     (ast_expression*)intrin->fold->imm_float[1],
1200                     (ast_expression*)ast_binary_new(
1201                         intrin_ctx(intrin),
1202                         INSTR_MUL_F,
1203                         (ast_expression*)eps,
1204                         (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1205                     )
1206                 ),
1207                 (ast_expression*)intrin->fold->imm_float[1]
1208             ),
1209             false,
1210             nullptr,
1211             (ast_expression*)ast_binstore_new(
1212                 intrin_ctx(intrin),
1213                 INSTR_STORE_F,
1214                 INSTR_DIV_F,
1215                 (ast_expression*)eps,
1216                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1217             )
1218         )
1219     );
1220
1221     /* return eps; */
1222     body->exprs.push_back(
1223         (ast_expression*)ast_return_new(
1224             intrin_ctx(intrin),
1225             (ast_expression*)eps
1226         )
1227     );
1228
1229     func->blocks.push_back(body);
1230     intrin_reg(intrin, value, func);
1231     return (ast_expression*)value;
1232 }
1233
1234 static ast_expression *intrin_nan(intrin_t *intrin) {
1235     /*
1236      * float nan(void) {
1237      *     float x = 0.0f;
1238      *     return x / x;
1239      * }
1240      */
1241     ast_value    *value  = nullptr;
1242     ast_value    *x      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1243     ast_function *func   = intrin_value(intrin, &value, "nan", TYPE_FLOAT);
1244     ast_block    *block  = ast_block_new(intrin_ctx(intrin));
1245
1246     block->locals.push_back(x);
1247
1248     block->exprs.push_back(
1249         (ast_expression*)ast_store_new(
1250             intrin_ctx(intrin),
1251             INSTR_STORE_F,
1252             (ast_expression*)x,
1253             (ast_expression*)intrin->fold->imm_float[0]
1254         )
1255     );
1256
1257     block->exprs.push_back(
1258         (ast_expression*)ast_return_new(
1259             intrin_ctx(intrin),
1260             (ast_expression*)ast_binary_new(
1261                 intrin_ctx(intrin),
1262                 INSTR_DIV_F,
1263                 (ast_expression*)x,
1264                 (ast_expression*)x
1265             )
1266         )
1267     );
1268
1269     func->blocks.push_back(block);
1270     intrin_reg(intrin, value, func);
1271     return (ast_expression*)value;
1272 }
1273
1274 static ast_expression *intrin_inf(intrin_t *intrin) {
1275     /*
1276      * float inf(void) {
1277      *     float x = 1.0f;
1278      *     float y = 0.0f;
1279      *     return x / y;
1280      * }
1281      */
1282     ast_value    *value  = nullptr;
1283     ast_value    *x      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1284     ast_value    *y      = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
1285     ast_function *func   = intrin_value(intrin, &value, "inf", TYPE_FLOAT);
1286     ast_block    *block  = ast_block_new(intrin_ctx(intrin));
1287     size_t        i;
1288
1289     block->locals.push_back(x);
1290     block->locals.push_back(y);
1291
1292     /* to keep code size down */
1293     for (i = 0; i <= 1; i++) {
1294         block->exprs.push_back(
1295             (ast_expression*)ast_store_new(
1296                 intrin_ctx(intrin),
1297                 INSTR_STORE_F,
1298                 (ast_expression*)((i == 0) ? x : y),
1299                 (ast_expression*)intrin->fold->imm_float[i]
1300             )
1301         );
1302     }
1303
1304     block->exprs.push_back(
1305         (ast_expression*)ast_return_new(
1306             intrin_ctx(intrin),
1307             (ast_expression*)ast_binary_new(
1308                 intrin_ctx(intrin),
1309                 INSTR_DIV_F,
1310                 (ast_expression*)x,
1311                 (ast_expression*)y
1312             )
1313         )
1314     );
1315
1316     func->blocks.push_back(block);
1317     intrin_reg(intrin, value, func);
1318     return (ast_expression*)value;
1319 }
1320
1321 static ast_expression *intrin_ln(intrin_t *intrin) {
1322     /*
1323      * float log(float power, float base) {
1324      *   float whole;
1325      *   float nth
1326      *   float sign = 1.0f;
1327      *   float eps  = epsilon();
1328      *
1329      *   if (power <= 1.0f || bbase <= 1.0) {
1330      *       if (power <= 0.0f || base <= 0.0f)
1331      *           return nan();
1332      *
1333      *       if (power < 1.0f) {
1334      *           power = 1.0f / power;
1335      *           sign *= -1.0f;
1336      *       }
1337      *
1338      *       if (base < 1.0f) {
1339      *           sign *= -1.0f;
1340      *           base  = 1.0f / base;
1341      *       }
1342      *   }
1343      *
1344      *   float A_i       = 1;
1345      *   float B_i       = 0;
1346      *   float A_iminus1 = 0;
1347      *   float B_iminus1 = 1;
1348      *
1349      *   for (;;) {
1350      *       whole = power;
1351      *       nth   = 0.0f;
1352      *
1353      *       while (whole >= base) {
1354      *           float base2    = base;
1355      *           float n2       = 1.0f;
1356      *           float newbase2 = base2 * base2;
1357      *
1358      *           while (whole >= newbase2) {
1359      *               base2     = newbase2;
1360      *               n2       *= 2;
1361      *               newbase2 *= newbase2;
1362      *           }
1363      *
1364      *           whole /= base2;
1365      *           nth += n2;
1366      *       }
1367      *
1368      *       float b_iplus1 = n;
1369      *       float A_iplus1 = b_iplus1 * A_i + A_iminus1;
1370      *       float B_iplus1 = b_iplus1 * B_i + B_iminus1;
1371      *
1372      *       A_iminus1 = A_i;
1373      *       B_iminus1 = B_i;
1374      *       A_i       = A_iplus1;
1375      *       B_i       = B_iplus1;
1376      *
1377      *       if (whole <= 1.0f + eps)
1378      *           break;
1379      *
1380      *       power = base;
1381      *       bower = whole;
1382      *   }
1383      *   return sign * A_i / B_i;
1384      * }
1385      */
1386
1387     ast_value    *value      = nullptr;
1388     ast_value    *power      = ast_value_new(intrin_ctx(intrin), "power",     TYPE_FLOAT);
1389     ast_value    *base       = ast_value_new(intrin_ctx(intrin), "base",      TYPE_FLOAT);
1390     ast_value    *whole      = ast_value_new(intrin_ctx(intrin), "whole",     TYPE_FLOAT);
1391     ast_value    *nth        = ast_value_new(intrin_ctx(intrin), "nth",       TYPE_FLOAT);
1392     ast_value    *sign       = ast_value_new(intrin_ctx(intrin), "sign",      TYPE_FLOAT);
1393     ast_value    *A_i        = ast_value_new(intrin_ctx(intrin), "A_i",       TYPE_FLOAT);
1394     ast_value    *B_i        = ast_value_new(intrin_ctx(intrin), "B_i",       TYPE_FLOAT);
1395     ast_value    *A_iminus1  = ast_value_new(intrin_ctx(intrin), "A_iminus1", TYPE_FLOAT);
1396     ast_value    *B_iminus1  = ast_value_new(intrin_ctx(intrin), "B_iminus1", TYPE_FLOAT);
1397     ast_value    *b_iplus1   = ast_value_new(intrin_ctx(intrin), "b_iplus1",  TYPE_FLOAT);
1398     ast_value    *A_iplus1   = ast_value_new(intrin_ctx(intrin), "A_iplus1",  TYPE_FLOAT);
1399     ast_value    *B_iplus1   = ast_value_new(intrin_ctx(intrin), "B_iplus1",  TYPE_FLOAT);
1400     ast_value    *eps        = ast_value_new(intrin_ctx(intrin), "eps",       TYPE_FLOAT);
1401     ast_value    *base2      = ast_value_new(intrin_ctx(intrin), "base2",     TYPE_FLOAT);
1402     ast_value    *n2         = ast_value_new(intrin_ctx(intrin), "n2",        TYPE_FLOAT);
1403     ast_value    *newbase2   = ast_value_new(intrin_ctx(intrin), "newbase2",  TYPE_FLOAT);
1404     ast_block    *block      = ast_block_new(intrin_ctx(intrin));
1405     ast_block    *plt1orblt1 = ast_block_new(intrin_ctx(intrin)); /* (power <= 1.0f || base <= 1.0f) */
1406     ast_block    *plt1       = ast_block_new(intrin_ctx(intrin)); /* (power < 1.0f) */
1407     ast_block    *blt1       = ast_block_new(intrin_ctx(intrin)); /* (base  < 1.0f) */
1408     ast_block    *forloop    = ast_block_new(intrin_ctx(intrin)); /* for(;;) */
1409     ast_block    *whileloop  = ast_block_new(intrin_ctx(intrin)); /* while (whole >= base) */
1410     ast_block    *nestwhile  = ast_block_new(intrin_ctx(intrin)); /* while (whole >= newbase2) */
1411     ast_function *func       = intrin_value(intrin, &value, "ln", TYPE_FLOAT);
1412     size_t        i;
1413
1414     value->expression.params.push_back(power);
1415     value->expression.params.push_back(base);
1416
1417     block->locals.push_back(whole);
1418     block->locals.push_back(nth);
1419     block->locals.push_back(sign);
1420     block->locals.push_back(eps);
1421     block->locals.push_back(A_i);
1422     block->locals.push_back(B_i);
1423     block->locals.push_back(A_iminus1);
1424     block->locals.push_back(B_iminus1);
1425
1426     /* sign = 1.0f; */
1427     block->exprs.push_back(
1428         (ast_expression*)ast_store_new(
1429             intrin_ctx(intrin),
1430             INSTR_STORE_F,
1431             (ast_expression*)sign,
1432             (ast_expression*)intrin->fold->imm_float[1]
1433         )
1434     );
1435
1436     /* eps = __builtin_epsilon(); */
1437     block->exprs.push_back(
1438         (ast_expression*)ast_store_new(
1439             intrin_ctx(intrin),
1440             INSTR_STORE_F,
1441             (ast_expression*)eps,
1442             (ast_expression*)ast_call_new(
1443                 intrin_ctx(intrin),
1444                 intrin_func_self(intrin, "__builtin_epsilon", "ln")
1445             )
1446         )
1447     );
1448
1449     /*
1450      * A_i       = 1;
1451      * B_i       = 0;
1452      * A_iminus1 = 0;
1453      * B_iminus1 = 1;
1454      */
1455     for (i = 0; i <= 1; i++) {
1456         int j;
1457         for (j = 1; j >= 0; j--) {
1458             block->exprs.push_back(
1459                 (ast_expression*)ast_store_new(
1460                     intrin_ctx(intrin),
1461                     INSTR_STORE_F,
1462                     (ast_expression*)((j) ? ((i) ? B_iminus1 : A_i)
1463                                           : ((i) ? A_iminus1 : B_i)),
1464                     (ast_expression*)intrin->fold->imm_float[j]
1465                 )
1466             );
1467         }
1468     }
1469
1470     /*
1471      * <plt1> = {
1472      *     power = 1.0f / power;
1473      *     sign *= -1.0f;
1474      * }
1475      * <blt1> = {
1476      *     base  = 1.0f / base;
1477      *     sign *= -1.0f;
1478      * }
1479      */
1480     for (i = 0; i <= 1; i++) {
1481         ((i) ? blt1 : plt1)->exprs.push_back(
1482             (ast_expression*)ast_store_new(
1483                 intrin_ctx(intrin),
1484                 INSTR_STORE_F,
1485                 (ast_expression*)((i) ? base : power),
1486                 (ast_expression*)ast_binary_new(
1487                     intrin_ctx(intrin),
1488                     INSTR_DIV_F,
1489                     (ast_expression*)intrin->fold->imm_float[1],
1490                     (ast_expression*)((i) ? base : power)
1491                 )
1492             )
1493         );
1494         plt1->exprs.push_back(
1495             (ast_expression*)ast_binstore_new(
1496                 intrin_ctx(intrin),
1497                 INSTR_STORE_F,
1498                 INSTR_MUL_F,
1499                 (ast_expression*)sign,
1500                 (ast_expression*)intrin->fold->imm_float[2]
1501             )
1502         );
1503     }
1504
1505     /*
1506      * <plt1orblt1> = {
1507      *     if (power <= 0.0 || base <= 0.0f)
1508      *         return __builtin_nan();
1509      *     if (power < 1.0f)
1510      *         <plt1>
1511      *     if (base < 1.0f)
1512      *         <blt1>
1513      * }
1514      */
1515     plt1orblt1->exprs.push_back(
1516         (ast_expression*)ast_ifthen_new(
1517             intrin_ctx(intrin),
1518             (ast_expression*)ast_binary_new(
1519                 intrin_ctx(intrin),
1520                 INSTR_OR,
1521                 (ast_expression*)ast_binary_new(
1522                     intrin_ctx(intrin),
1523                     INSTR_LE,
1524                     (ast_expression*)power,
1525                     (ast_expression*)intrin->fold->imm_float[0]
1526                 ),
1527                 (ast_expression*)ast_binary_new(
1528                     intrin_ctx(intrin),
1529                     INSTR_LE,
1530                     (ast_expression*)base,
1531                     (ast_expression*)intrin->fold->imm_float[0]
1532                 )
1533             ),
1534             (ast_expression*)ast_return_new(
1535                 intrin_ctx(intrin),
1536                 (ast_expression*)ast_call_new(
1537                     intrin_ctx(intrin),
1538                     intrin_func_self(intrin, "__builtin_nan", "ln")
1539                 )
1540             ),
1541             nullptr
1542         )
1543     );
1544
1545     for (i = 0; i <= 1; i++) {
1546         plt1orblt1->exprs.push_back(
1547             (ast_expression*)ast_ifthen_new(
1548                 intrin_ctx(intrin),
1549                 (ast_expression*)ast_binary_new(
1550                     intrin_ctx(intrin),
1551                     INSTR_LT,
1552                     (ast_expression*)((i) ? base : power),
1553                     (ast_expression*)intrin->fold->imm_float[1]
1554                 ),
1555                 (ast_expression*)((i) ? blt1 : plt1),
1556                 nullptr
1557             )
1558         );
1559     }
1560
1561     block->exprs.push_back((ast_expression*)plt1orblt1);
1562
1563
1564     /* whole = power; */
1565     forloop->exprs.push_back(
1566         (ast_expression*)ast_store_new(
1567             intrin_ctx(intrin),
1568             INSTR_STORE_F,
1569             (ast_expression*)whole,
1570             (ast_expression*)power
1571         )
1572     );
1573
1574     /* nth = 0.0f; */
1575     forloop->exprs.push_back(
1576         (ast_expression*)ast_store_new(
1577             intrin_ctx(intrin),
1578             INSTR_STORE_F,
1579             (ast_expression*)nth,
1580             (ast_expression*)intrin->fold->imm_float[0]
1581         )
1582     );
1583
1584     /* base2 = base; */
1585     whileloop->exprs.push_back(
1586         (ast_expression*)ast_store_new(
1587             intrin_ctx(intrin),
1588             INSTR_STORE_F,
1589             (ast_expression*)base2,
1590             (ast_expression*)base
1591         )
1592     );
1593
1594     /* n2 = 1.0f; */
1595     whileloop->exprs.push_back(
1596         (ast_expression*)ast_store_new(
1597             intrin_ctx(intrin),
1598             INSTR_STORE_F,
1599             (ast_expression*)n2,
1600             (ast_expression*)intrin->fold->imm_float[1]
1601         )
1602     );
1603
1604     /* newbase2 = base2 * base2; */
1605     whileloop->exprs.push_back(
1606         (ast_expression*)ast_store_new(
1607             intrin_ctx(intrin),
1608             INSTR_STORE_F,
1609             (ast_expression*)newbase2,
1610             (ast_expression*)ast_binary_new(
1611                 intrin_ctx(intrin),
1612                 INSTR_MUL_F,
1613                 (ast_expression*)base2,
1614                 (ast_expression*)base2
1615             )
1616         )
1617     );
1618
1619     /* while loop locals */
1620     whileloop->locals.push_back(base2);
1621     whileloop->locals.push_back(n2);
1622     whileloop->locals.push_back(newbase2);
1623
1624     /* base2 = newbase2; */
1625     nestwhile->exprs.push_back(
1626         (ast_expression*)ast_store_new(
1627             intrin_ctx(intrin),
1628             INSTR_STORE_F,
1629             (ast_expression*)base2,
1630             (ast_expression*)newbase2
1631         )
1632     );
1633
1634     /* n2 *= 2; */
1635     nestwhile->exprs.push_back(
1636         (ast_expression*)ast_binstore_new(
1637             intrin_ctx(intrin),
1638             INSTR_STORE_F,
1639             INSTR_MUL_F,
1640             (ast_expression*)n2,
1641             (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1642         )
1643     );
1644
1645     /* newbase2 *= newbase2; */
1646     nestwhile->exprs.push_back(
1647         (ast_expression*)ast_binstore_new(
1648             intrin_ctx(intrin),
1649             INSTR_STORE_F,
1650             INSTR_MUL_F,
1651             (ast_expression*)newbase2,
1652             (ast_expression*)newbase2
1653         )
1654     );
1655
1656     /* while (whole >= newbase2) */
1657     whileloop->exprs.push_back(
1658         (ast_expression*)ast_loop_new(
1659             intrin_ctx(intrin),
1660             nullptr,
1661             (ast_expression*)ast_binary_new(
1662                 intrin_ctx(intrin),
1663                 INSTR_GE,
1664                 (ast_expression*)whole,
1665                 (ast_expression*)newbase2
1666             ),
1667             false,
1668             nullptr,
1669             false,
1670             nullptr,
1671             (ast_expression*)nestwhile
1672         )
1673     );
1674
1675     /* whole /= base2; */
1676     whileloop->exprs.push_back(
1677         (ast_expression*)ast_binstore_new(
1678             intrin_ctx(intrin),
1679             INSTR_STORE_F,
1680             INSTR_DIV_F,
1681             (ast_expression*)whole,
1682             (ast_expression*)base2
1683         )
1684     );
1685
1686     /* nth += n2; */
1687     whileloop->exprs.push_back(
1688         (ast_expression*)ast_binstore_new(
1689             intrin_ctx(intrin),
1690             INSTR_STORE_F,
1691             INSTR_ADD_F,
1692             (ast_expression*)nth,
1693             (ast_expression*)n2
1694         )
1695     );
1696
1697     /* while (whole >= base) */
1698     forloop->exprs.push_back(
1699         (ast_expression*)ast_loop_new(
1700             intrin_ctx(intrin),
1701             nullptr,
1702             (ast_expression*)ast_binary_new(
1703                 intrin_ctx(intrin),
1704                 INSTR_GE,
1705                 (ast_expression*)whole,
1706                 (ast_expression*)base
1707             ),
1708             false,
1709             nullptr,
1710             false,
1711             nullptr,
1712             (ast_expression*)whileloop
1713         )
1714     );
1715
1716     forloop->locals.push_back(b_iplus1);
1717     forloop->locals.push_back(A_iplus1);
1718     forloop->locals.push_back(B_iplus1);
1719
1720     /* b_iplus1 = nth; */
1721     forloop->exprs.push_back(
1722         (ast_expression*)ast_store_new(
1723             intrin_ctx(intrin),
1724             INSTR_STORE_F,
1725             (ast_expression*)b_iplus1,
1726             (ast_expression*)nth
1727         )
1728     );
1729
1730     /*
1731      * A_iplus1 = b_iplus1 * A_i + A_iminus1;
1732      * B_iplus1 = b_iplus1 * B_i + B_iminus1;
1733      */
1734     for (i = 0; i <= 1; i++) {
1735         forloop->exprs.push_back(
1736             (ast_expression*)ast_store_new(
1737                 intrin_ctx(intrin),
1738                 INSTR_STORE_F,
1739                 (ast_expression*)((i) ? B_iplus1 : A_iplus1),
1740                 (ast_expression*)ast_binary_new(
1741                     intrin_ctx(intrin),
1742                     INSTR_ADD_F,
1743                     (ast_expression*)ast_binary_new(
1744                         intrin_ctx(intrin),
1745                         INSTR_MUL_F,
1746                         (ast_expression*)b_iplus1,
1747                         (ast_expression*) ((i) ? B_i : A_i)
1748                     ),
1749                     (ast_expression*)((i) ? B_iminus1 : A_iminus1)
1750                 )
1751             )
1752         );
1753     }
1754
1755     /*
1756      * A_iminus1 = A_i;
1757      * B_iminus1 = B_i;
1758      */
1759     for (i = 0; i <= 1; i++) {
1760         forloop->exprs.push_back(
1761             (ast_expression*)ast_store_new(
1762                 intrin_ctx(intrin),
1763                 INSTR_STORE_F,
1764                 (ast_expression*)((i) ? B_iminus1 : A_iminus1),
1765                 (ast_expression*)((i) ? B_i       : A_i)
1766             )
1767         );
1768     }
1769
1770     /*
1771      * A_i = A_iplus1;
1772      * B_i = B_iplus1;
1773      */
1774     for (i = 0; i <= 1; i++) {
1775         forloop->exprs.push_back(
1776             (ast_expression*)ast_store_new(
1777                 intrin_ctx(intrin),
1778                 INSTR_STORE_F,
1779                 (ast_expression*)((i) ? B_i      : A_i),
1780                 (ast_expression*)((i) ? B_iplus1 : A_iplus1)
1781             )
1782         );
1783     }
1784
1785     /*
1786      * if (whole <= 1.0f + eps)
1787      *     break;
1788      */
1789     forloop->exprs.push_back(
1790         (ast_expression*)ast_ifthen_new(
1791             intrin_ctx(intrin),
1792             (ast_expression*)ast_binary_new(
1793                 intrin_ctx(intrin),
1794                 INSTR_LE,
1795                 (ast_expression*)whole,
1796                 (ast_expression*)ast_binary_new(
1797                     intrin_ctx(intrin),
1798                     INSTR_ADD_F,
1799                     (ast_expression*)intrin->fold->imm_float[1],
1800                     (ast_expression*)eps
1801                 )
1802             ),
1803             (ast_expression*)ast_breakcont_new(
1804                 intrin_ctx(intrin),
1805                 false,
1806                 0
1807             ),
1808             nullptr
1809         )
1810     );
1811
1812     /*
1813      * power = base;
1814      * base  = whole;
1815      */
1816     for (i = 0; i <= 1; i++) {
1817         forloop->exprs.push_back(
1818             (ast_expression*)ast_store_new(
1819                 intrin_ctx(intrin),
1820                 INSTR_STORE_F,
1821                 (ast_expression*)((i) ? base  : power),
1822                 (ast_expression*)((i) ? whole : base)
1823             )
1824         );
1825     }
1826
1827     /* add the for loop block */
1828     block->exprs.push_back(
1829         (ast_expression*)ast_loop_new(
1830             intrin_ctx(intrin),
1831             nullptr,
1832             /* for(; 1; ) ?? (can this be nullptr too?) */
1833             (ast_expression*)intrin->fold->imm_float[1],
1834             false,
1835             nullptr,
1836             false,
1837             nullptr,
1838             (ast_expression*)forloop
1839         )
1840     );
1841
1842     /* return sign * A_i / B_il */
1843     block->exprs.push_back(
1844         (ast_expression*)ast_return_new(
1845             intrin_ctx(intrin),
1846             (ast_expression*)ast_binary_new(
1847                 intrin_ctx(intrin),
1848                 INSTR_MUL_F,
1849                 (ast_expression*)sign,
1850                 (ast_expression*)ast_binary_new(
1851                     intrin_ctx(intrin),
1852                     INSTR_DIV_F,
1853                     (ast_expression*)A_i,
1854                     (ast_expression*)B_i
1855                 )
1856             )
1857         )
1858     );
1859
1860     func->blocks.push_back(block);
1861     intrin_reg(intrin, value, func);
1862     return (ast_expression*)value;
1863 }
1864
1865 static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) {
1866     ast_value    *value  = nullptr;
1867     ast_call     *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", name));
1868     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1869     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1870     ast_function *func   = intrin_value(intrin, &value, name, TYPE_FLOAT);
1871
1872     value->expression.params.push_back(arg1);
1873
1874     callln->params.push_back((ast_expression*)arg1);
1875     callln->params.push_back((ast_expression*)fold_constgen_float(intrin->fold, base, false));
1876
1877     body->exprs.push_back(
1878         (ast_expression*)ast_return_new(
1879             intrin_ctx(intrin),
1880             (ast_expression*)callln
1881         )
1882     );
1883
1884     func->blocks.push_back(body);
1885     intrin_reg(intrin, value, func);
1886     return (ast_expression*)value;
1887 }
1888
1889 static ast_expression *intrin_log(intrin_t *intrin) {
1890     return intrin_log_variant(intrin, "log", 2.7182818284590452354);
1891 }
1892 static ast_expression *intrin_log10(intrin_t *intrin) {
1893     return intrin_log_variant(intrin, "log10", 10);
1894 }
1895 static ast_expression *intrin_log2(intrin_t *intrin) {
1896     return intrin_log_variant(intrin, "log2", 2);
1897 }
1898 static ast_expression *intrin_logb(intrin_t *intrin) {
1899     /* FLT_RADIX == 2 for now */
1900     return intrin_log_variant(intrin, "log2", 2);
1901 }
1902
1903 static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) {
1904     /*
1905      * float [shift] (float a, float b) {
1906      *   return floor(a [instr] pow(2, b));
1907      */
1908     ast_value    *value     = nullptr;
1909     ast_call     *callpow   = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
1910     ast_call     *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", name));
1911     ast_value    *a         = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
1912     ast_value    *b         = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
1913     ast_block    *body      = ast_block_new(intrin_ctx(intrin));
1914     ast_function *func      = intrin_value(intrin, &value, name, TYPE_FLOAT);
1915
1916     value->expression.params.push_back(a);
1917     value->expression.params.push_back(b);
1918
1919     /* <callpow> = pow(2, b) */
1920     callpow->params.push_back((ast_expression*)intrin->fold->imm_float[3]);
1921     callpow->params.push_back((ast_expression*)b);
1922
1923     /* <callfloor> = floor(a [instr] <callpow>) */
1924     callfloor->params.push_back(
1925         (ast_expression*)ast_binary_new(
1926             intrin_ctx(intrin),
1927             instr,
1928             (ast_expression*)a,
1929             (ast_expression*)callpow
1930         )
1931     );
1932
1933     /* return <callfloor> */
1934     body->exprs.push_back(
1935         (ast_expression*)ast_return_new(
1936             intrin_ctx(intrin),
1937             (ast_expression*)callfloor
1938         )
1939     );
1940
1941     func->blocks.push_back(body);
1942     intrin_reg(intrin, value, func);
1943     return (ast_expression*)value;
1944 }
1945
1946 static ast_expression *intrin_lshift(intrin_t *intrin) {
1947     return intrin_shift_variant(intrin, "lshift", INSTR_MUL_F);
1948 }
1949
1950 static ast_expression *intrin_rshift(intrin_t *intrin) {
1951     return intrin_shift_variant(intrin, "rshift", INSTR_DIV_F);
1952 }
1953
1954 /*
1955  * TODO: make static (and handle ast_type_string) here for the builtin
1956  * instead of in SYA parse close.
1957  */
1958 ast_expression *intrin_debug_typestring(intrin_t *intrin) {
1959     (void)intrin;
1960     return (ast_expression*)0x1;
1961 }
1962
1963 static const intrin_func_t intrinsics[] = {
1964     {&intrin_isfinite,         "__builtin_isfinite",         "isfinite", 1},
1965     {&intrin_isinf,            "__builtin_isinf",            "isinf",    1},
1966     {&intrin_isnan,            "__builtin_isnan",            "isnan",    1},
1967     {&intrin_isnormal,         "__builtin_isnormal",         "isnormal", 1},
1968     {&intrin_signbit,          "__builtin_signbit",          "signbit",  1},
1969     {&intrin_acosh,            "__builtin_acosh",            "acosh",    1},
1970     {&intrin_asinh,            "__builtin_asinh",            "asinh",    1},
1971     {&intrin_atanh,            "__builtin_atanh",            "atanh",    1},
1972     {&intrin_exp,              "__builtin_exp",              "exp",      1},
1973     {&intrin_exp2,             "__builtin_exp2",             "exp2",     1},
1974     {&intrin_expm1,            "__builtin_expm1",            "expm1",    1},
1975     {&intrin_mod,              "__builtin_mod",              "mod",      2},
1976     {&intrin_pow,              "__builtin_pow",              "pow",      2},
1977     {&intrin_fabs,             "__builtin_fabs",             "fabs",     1},
1978     {&intrin_log,              "__builtin_log",              "log",      1},
1979     {&intrin_log10,            "__builtin_log10",            "log10",    1},
1980     {&intrin_log2,             "__builtin_log2",             "log2",     1},
1981     {&intrin_logb,             "__builtin_logb",             "logb",     1},
1982     {&intrin_lshift,           "__builtin_lshift",           "",         2},
1983     {&intrin_rshift,           "__builtin_rshift",           "",         2},
1984     {&intrin_epsilon,          "__builtin_epsilon",          "",         0},
1985     {&intrin_nan,              "__builtin_nan",              "",         0},
1986     {&intrin_inf,              "__builtin_inf",              "",         0},
1987     {&intrin_ln,               "__builtin_ln",               "",         2},
1988     {&intrin_debug_typestring, "__builtin_debug_typestring", "",         0},
1989     {&intrin_nullfunc,         "#nullfunc",                  "",         0}
1990 };
1991
1992 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
1993     va_list ap;
1994     va_start(ap, fmt);
1995     vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
1996     va_end(ap);
1997 }
1998
1999 /* exposed */
2000 intrin_t *intrin_init(parser_t *parser) {
2001     intrin_t *intrin = new intrin_t;
2002
2003     intrin->parser = parser;
2004     intrin->fold = parser->fold;
2005
2006     for (auto &it : intrinsics) {
2007         intrin->intrinsics.push_back(it);
2008         intrin->generated.push_back(nullptr);
2009     }
2010
2011     return intrin;
2012 }
2013
2014 void intrin_cleanup(intrin_t *intrin) {
2015     delete intrin;
2016 }
2017
2018 ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
2019     if (!value || !value->name)
2020         return nullptr;
2021     for (auto &it : intrin->intrinsics) {
2022         if (!strcmp(value->name, it.name))
2023             return (vec_size(exprs) != it.args)
2024                         ? nullptr
2025                         : fold_intrin(intrin->fold, value->name + 10, exprs);
2026     }
2027     return nullptr;
2028 }
2029
2030 static GMQCC_INLINE ast_expression *intrin_func_try(intrin_t *intrin, size_t offset, const char *compare) {
2031     for (auto &it : intrin->intrinsics) {
2032         const size_t index = &it - &intrin->intrinsics[0];
2033         if (strcmp(*(char **)((char *)&it + offset), compare))
2034             continue;
2035         if (intrin->generated[index])
2036             return intrin->generated[index];
2037         return intrin->generated[index] = it.intrin(intrin);
2038     }
2039     return nullptr;
2040 }
2041
2042 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
2043     ast_expression *find;
2044     /* try current first */
2045     if ((find = parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
2046         for (auto &it : intrin->parser->functions)
2047             if (((ast_value*)find)->name && !strcmp(it->name, ((ast_value*)find)->name) && it->builtin < 0)
2048                 return find;
2049     /* try name second */
2050     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, name),  name)))
2051         return find;
2052     /* try alias third */
2053     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
2054         return find;
2055
2056     if (from) {
2057         intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
2058         return intrin_func_self(intrin, "#nullfunc", nullptr);
2059     }
2060     return nullptr;
2061 }
2062
2063 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
2064     return intrin_func_self(intrin, name, nullptr);
2065 }