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