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