4 #define intrin_ctx(I) parser_ctx((I)->parser)
6 static GMQCC_INLINE ast_function *intrin_value(intrin_t *intrin, ast_value **out, const char *name, qcint_t vtype) {
7 ast_value *value = NULL;
8 ast_function *func = NULL;
12 util_snprintf(buffer, sizeof(buffer), "__builtin_%s", name);
13 util_snprintf(stype, sizeof(stype), "<%s>", type_name[vtype]);
15 value = ast_value_new(intrin_ctx(intrin), buffer, TYPE_FUNCTION);
16 value->intrinsic = true;
17 value->expression.next = (ast_expression*)ast_value_new(intrin_ctx(intrin), stype, vtype);
18 func = ast_function_new(intrin_ctx(intrin), buffer, value);
19 value->expression.flags |= AST_FLAG_ERASEABLE;
25 static GMQCC_INLINE void intrin_reg(intrin_t *intrin, ast_value *const value, ast_function *const func) {
26 intrin->parser->functions.push_back(func);
27 intrin->parser->globals.push_back((ast_expression*)value);
30 #define QC_POW_EPSILON 0.00001f
33 * since some intrinsics depend on each other there is the possibility
34 * that an intrinsic will fail to get a 'depended' function that a
35 * builtin needs, causing some dependency in the chain to have a NULL
36 * function. This will cause a segmentation fault at code generation,
37 * even though an error was raised. To contiue to allow it (instead
38 * of stopping compilation right away). We need to return from the
39 * parser, before compilation stops after all the collected errors.
41 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from);
42 static ast_expression *intrin_nullfunc(intrin_t *intrin) {
43 ast_value *value = NULL;
44 ast_function *func = intrin_value(intrin, &value, NULL, TYPE_VOID);
45 intrin_reg(intrin, value, func);
46 return (ast_expression*)value;
49 static ast_expression *intrin_isfinite(intrin_t *intrin) {
51 * float isfinite(float x) {
52 * return !(isnan(x) || isinf(x));
55 ast_value *value = NULL;
56 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
57 ast_function *func = intrin_value(intrin, &value, "isfinite", TYPE_FLOAT);
58 ast_call *callisnan = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isnan", "isfinite"));
59 ast_call *callisinf = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isinf", "isfinite"));
60 ast_block *block = ast_block_new(intrin_ctx(intrin));
63 value->expression.params.push_back(x);
65 /* <callisnan> = isnan(x); */
66 callisnan->params.push_back((ast_expression*)x);
68 /* <callisinf> = isinf(x); */
69 callisinf->params.push_back((ast_expression*)x);
71 /* return (!<callisnan> || <callisinf>); */
72 block->exprs.push_back(
73 (ast_expression*)ast_return_new(
75 (ast_expression*)ast_unary_new(
78 (ast_expression*)ast_binary_new(
81 (ast_expression*)callisnan,
82 (ast_expression*)callisinf
88 vec_push(func->blocks, block);
89 intrin_reg(intrin, value, func);
91 return (ast_expression*)value;;
94 static ast_expression *intrin_isinf(intrin_t *intrin) {
96 * float isinf(float x) {
97 * return (x != 0.0) && (x + x == x);
100 ast_value *value = NULL;
101 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
102 ast_block *body = ast_block_new(intrin_ctx(intrin));
103 ast_function *func = intrin_value(intrin, &value, "isinf", TYPE_FLOAT);
105 body->exprs.push_back(
106 (ast_expression*)ast_return_new(
108 (ast_expression*)ast_binary_new(
111 (ast_expression*)ast_binary_new(
115 (ast_expression*)intrin->fold->imm_float[0]
117 (ast_expression*)ast_binary_new(
120 (ast_expression*)ast_binary_new(
132 value->expression.params.push_back(x);
133 vec_push(func->blocks, body);
135 intrin_reg(intrin, value, func);
137 return (ast_expression*)value;
140 static ast_expression *intrin_isnan(intrin_t *intrin) {
142 * float isnan(float x) {
146 * return (x != local);
149 ast_value *value = NULL;
150 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
151 ast_value *local = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
152 ast_block *body = ast_block_new(intrin_ctx(intrin));
153 ast_function *func = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
155 body->locals.push_back(local);
156 body->exprs.push_back(
157 (ast_expression*)ast_store_new(
160 (ast_expression*)local,
161 (ast_expression*)arg1
165 body->exprs.push_back(
166 (ast_expression*)ast_return_new(
168 (ast_expression*)ast_binary_new(
171 (ast_expression*)arg1,
172 (ast_expression*)local
177 value->expression.params.push_back(arg1);
178 vec_push(func->blocks, body);
180 intrin_reg(intrin, value, func);
182 return (ast_expression*)value;
185 static ast_expression *intrin_isnormal(intrin_t *intrin) {
187 * float isnormal(float x) {
188 * return isfinite(x);
191 ast_value *value = NULL;
192 ast_call *callisfinite = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "isfinite", "isnormal"));
193 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
194 ast_block *body = ast_block_new(intrin_ctx(intrin));
195 ast_function *func = intrin_value(intrin, &value, "isnormal", TYPE_FLOAT);
197 value->expression.params.push_back(x);
198 callisfinite->params.push_back((ast_expression*)x);
200 /* return <callisfinite> */
201 body->exprs.push_back(
202 (ast_expression*)ast_return_new(
204 (ast_expression*)callisfinite
208 vec_push(func->blocks, body);
209 intrin_reg(intrin, value, func);
210 return (ast_expression*)value;
213 static ast_expression *intrin_signbit(intrin_t *intrin) {
215 * float signbit(float x) {
219 ast_value *value = NULL;
220 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
221 ast_block *body = ast_block_new(intrin_ctx(intrin));
222 ast_function *func = intrin_value(intrin, &value, "signbit", TYPE_FLOAT);
224 value->expression.params.push_back(x);
226 /* return (x < 0); */
227 body->exprs.push_back(
228 (ast_expression*)ast_return_new(
230 (ast_expression*)ast_ternary_new(
232 (ast_expression*)ast_binary_new(
236 (ast_expression*)intrin->fold->imm_float[0]
238 (ast_expression*)intrin->fold->imm_float[1],
239 (ast_expression*)intrin->fold->imm_float[0]
244 vec_push(func->blocks, body);
245 intrin_reg(intrin, value, func);
246 return (ast_expression*)value;
249 static ast_expression *intrin_acosh(intrin_t *intrin) {
251 * float acosh(float x) {
252 * return log(x + sqrt((x * x) - 1));
255 ast_value *value = NULL;
256 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
257 ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "acosh"));
258 ast_call *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "acosh"));
259 ast_block *body = ast_block_new(intrin_ctx(intrin));
260 ast_function *func = intrin_value(intrin, &value, "acosh", TYPE_FLOAT);
262 value->expression.params.push_back(x);
264 /* <callsqrt> = sqrt((x * x) - 1); */
265 callsqrt->params.push_back(
266 (ast_expression*)ast_binary_new(
269 (ast_expression*)ast_binary_new(
275 (ast_expression*)intrin->fold->imm_float[1]
279 /* <calllog> = log(x + <callsqrt>); */
280 calllog->params.push_back(
281 (ast_expression*)ast_binary_new(
285 (ast_expression*)callsqrt
289 /* return <calllog>; */
290 body->exprs.push_back(
291 (ast_expression*)ast_return_new(
293 (ast_expression*)calllog
297 vec_push(func->blocks, body);
298 intrin_reg(intrin, value, func);
299 return (ast_expression*)value;
302 static ast_expression *intrin_asinh(intrin_t *intrin) {
304 * float asinh(float x) {
305 * return log(x + sqrt((x * x) + 1));
308 ast_value *value = NULL;
309 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
310 ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "asinh"));
311 ast_call *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "asinh"));
312 ast_block *body = ast_block_new(intrin_ctx(intrin));
313 ast_function *func = intrin_value(intrin, &value, "asinh", TYPE_FLOAT);
315 value->expression.params.push_back(x);
317 /* <callsqrt> = sqrt((x * x) + 1); */
318 callsqrt->params.push_back(
319 (ast_expression*)ast_binary_new(
322 (ast_expression*)ast_binary_new(
328 (ast_expression*)intrin->fold->imm_float[1]
332 /* <calllog> = log(x + <callsqrt>); */
333 calllog->params.push_back(
334 (ast_expression*)ast_binary_new(
338 (ast_expression*)callsqrt
342 /* return <calllog>; */
343 body->exprs.push_back(
344 (ast_expression*)ast_return_new(
346 (ast_expression*)calllog
350 vec_push(func->blocks, body);
351 intrin_reg(intrin, value, func);
352 return (ast_expression*)value;
355 static ast_expression *intrin_atanh(intrin_t *intrin) {
357 * float atanh(float x) {
358 * return 0.5 * log((1 + x) / (1 - x))
361 ast_value *value = NULL;
362 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
363 ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "atanh"));
364 ast_block *body = ast_block_new(intrin_ctx(intrin));
365 ast_function *func = intrin_value(intrin, &value, "atanh", TYPE_FLOAT);
367 value->expression.params.push_back(x);
369 /* <callog> = log((1 + x) / (1 - x)); */
370 calllog->params.push_back(
371 (ast_expression*)ast_binary_new(
374 (ast_expression*)ast_binary_new(
377 (ast_expression*)intrin->fold->imm_float[1],
380 (ast_expression*)ast_binary_new(
383 (ast_expression*)intrin->fold->imm_float[1],
389 /* return 0.5 * <calllog>; */
390 body->exprs.push_back(
391 (ast_expression*)ast_binary_new(
394 (ast_expression*)fold_constgen_float(intrin->fold, 0.5, false),
395 (ast_expression*)calllog
399 vec_push(func->blocks, body);
400 intrin_reg(intrin, value, func);
401 return (ast_expression*)value;
404 static ast_expression *intrin_exp(intrin_t *intrin) {
406 * float exp(float x) {
410 * for (i = 1; i < 200; ++i)
411 * sum += (acc *= x / i);
416 ast_value *value = NULL;
417 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
418 ast_value *sum = ast_value_new(intrin_ctx(intrin), "sum", TYPE_FLOAT);
419 ast_value *acc = ast_value_new(intrin_ctx(intrin), "acc", TYPE_FLOAT);
420 ast_value *i = ast_value_new(intrin_ctx(intrin), "i", TYPE_FLOAT);
421 ast_block *body = ast_block_new(intrin_ctx(intrin));
422 ast_function *func = intrin_value(intrin, &value, "exp", TYPE_FLOAT);
424 value->expression.params.push_back(x);
426 body->locals.push_back(sum);
427 body->locals.push_back(acc);
428 body->locals.push_back(i);
431 body->exprs.push_back(
432 (ast_expression*)ast_store_new(
435 (ast_expression*)sum,
436 (ast_expression*)intrin->fold->imm_float[1]
441 body->exprs.push_back(
442 (ast_expression*)ast_store_new(
445 (ast_expression*)acc,
446 (ast_expression*)intrin->fold->imm_float[1]
451 * for (i = 1; i < 200; ++i)
452 * sum += (acc *= x / i);
454 body->exprs.push_back(
455 (ast_expression*)ast_loop_new(
458 (ast_expression*)ast_store_new(
462 (ast_expression*)intrin->fold->imm_float[1]
465 (ast_expression*)ast_binary_new(
469 (ast_expression*)fold_constgen_float(intrin->fold, 200.0f, false)
475 (ast_expression*)ast_binstore_new(
480 (ast_expression*)intrin->fold->imm_float[1]
482 /* sum += (acc *= (x / i)) */
483 (ast_expression*)ast_binstore_new(
487 (ast_expression*)sum,
488 (ast_expression*)ast_binstore_new(
492 (ast_expression*)acc,
493 (ast_expression*)ast_binary_new(
505 body->exprs.push_back(
506 (ast_expression*)ast_return_new(
512 vec_push(func->blocks, body);
514 intrin_reg(intrin, value, func);
515 return (ast_expression*)value;
518 static ast_expression *intrin_exp2(intrin_t *intrin) {
520 * float exp2(float x) {
524 ast_value *value = NULL;
525 ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp2"));
526 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
527 ast_block *body = ast_block_new(intrin_ctx(intrin));
528 ast_function *func = intrin_value(intrin, &value, "exp2", TYPE_FLOAT);
530 value->expression.params.push_back(arg1);
532 callpow->params.push_back((ast_expression*)intrin->fold->imm_float[3]);
533 callpow->params.push_back((ast_expression*)arg1);
535 /* return <callpow> */
536 body->exprs.push_back(
537 (ast_expression*)ast_return_new(
539 (ast_expression*)callpow
543 vec_push(func->blocks, body);
545 intrin_reg(intrin, value, func);
546 return (ast_expression*)value;
549 static ast_expression *intrin_expm1(intrin_t *intrin) {
551 * float expm1(float x) {
555 ast_value *value = NULL;
556 ast_call *callexp = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "exp", "expm1"));
557 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
558 ast_block *body = ast_block_new(intrin_ctx(intrin));
559 ast_function *func = intrin_value(intrin, &value, "expm1", TYPE_FLOAT);
561 value->expression.params.push_back(x);
563 /* <callexp> = exp(x); */
564 callexp->params.push_back((ast_expression*)x);
566 /* return <callexp> - 1; */
567 body->exprs.push_back(
568 (ast_expression*)ast_return_new(
570 (ast_expression*)ast_binary_new(
573 (ast_expression*)callexp,
574 (ast_expression*)intrin->fold->imm_float[1]
579 vec_push(func->blocks, body);
580 intrin_reg(intrin, value, func);
581 return (ast_expression*)value;
584 static ast_expression *intrin_pow(intrin_t *intrin) {
587 * float pow(float base, float exp) {
600 * return 1.0 / pow(base, -exp);
602 * result = pow(base, exp / 2);
603 * return result * result;
608 * square = sqrt(base);
609 * accumulate = square;
612 * while (fabs(mid - exp) > QC_POW_EPSILON) {
613 * square = sqrt(square);
616 * accumulate *= square;
619 * accumulate *= (1.0f / square);
621 * mid = (low + high) / 2;
626 ast_value *value = NULL;
627 ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
629 /* prepare some calls for later */
630 ast_call *callpow1 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(base, -exp) */
631 ast_call *callpow2 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(vase, exp / 2) */
632 ast_call *callsqrt1 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(base) */
633 ast_call *callsqrt2 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(square) */
634 ast_call *callfabs = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "fabs", "pow")); /* for fabs(mid - exp) */
636 /* prepare some blocks for later */
637 ast_block *expgt1 = ast_block_new(intrin_ctx(intrin));
638 ast_block *midltexp = ast_block_new(intrin_ctx(intrin));
639 ast_block *midltexpelse = ast_block_new(intrin_ctx(intrin));
640 ast_block *whileblock = ast_block_new(intrin_ctx(intrin));
642 /* float pow(float base, float exp) */
643 ast_value *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
644 ast_value *exp = ast_value_new(intrin_ctx(intrin), "exp", TYPE_FLOAT);
646 ast_block *body = ast_block_new(intrin_ctx(intrin));
656 ast_value *result = ast_value_new(intrin_ctx(intrin), "result", TYPE_FLOAT);
657 ast_value *low = ast_value_new(intrin_ctx(intrin), "low", TYPE_FLOAT);
658 ast_value *high = ast_value_new(intrin_ctx(intrin), "high", TYPE_FLOAT);
659 ast_value *square = ast_value_new(intrin_ctx(intrin), "square", TYPE_FLOAT);
660 ast_value *accumulate = ast_value_new(intrin_ctx(intrin), "accumulate", TYPE_FLOAT);
661 ast_value *mid = ast_value_new(intrin_ctx(intrin), "mid", TYPE_FLOAT);
662 body->locals.push_back(result);
663 body->locals.push_back(low);
664 body->locals.push_back(high);
665 body->locals.push_back(square);
666 body->locals.push_back(accumulate);
667 body->locals.push_back(mid);
669 value->expression.params.push_back(base);
670 value->expression.params.push_back(exp);
676 body->exprs.push_back(
677 (ast_expression*)ast_ifthen_new(
679 (ast_expression*)ast_binary_new(
682 (ast_expression*)exp,
683 (ast_expression*)intrin->fold->imm_float[0]
685 (ast_expression*)ast_return_new(
687 (ast_expression*)intrin->fold->imm_float[1]
697 body->exprs.push_back(
698 (ast_expression*)ast_ifthen_new(
700 (ast_expression*)ast_binary_new(
703 (ast_expression*)exp,
704 (ast_expression*)intrin->fold->imm_float[1]
706 (ast_expression*)ast_return_new(
708 (ast_expression*)base
714 /* <callpow1> = pow(base, -exp) */
715 callpow1->params.push_back((ast_expression*)base);
716 callpow1->params.push_back(
717 (ast_expression*)ast_unary_new(
726 * return 1.0 / <callpow1>;
728 body->exprs.push_back(
729 (ast_expression*)ast_ifthen_new(
731 (ast_expression*)ast_binary_new(
734 (ast_expression*)exp,
735 (ast_expression*)intrin->fold->imm_float[0]
737 (ast_expression*)ast_return_new(
739 (ast_expression*)ast_binary_new(
742 (ast_expression*)intrin->fold->imm_float[1],
743 (ast_expression*)callpow1
750 /* <callpow2> = pow(base, exp / 2) */
751 callpow2->params.push_back((ast_expression*)base);
752 callpow2->params.push_back(
753 (ast_expression*)ast_binary_new(
756 (ast_expression*)exp,
757 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
763 * result = <callpow2>;
764 * return result * result;
767 expgt1->exprs.push_back(
768 (ast_expression*)ast_store_new(
771 (ast_expression*)result,
772 (ast_expression*)callpow2
775 expgt1->exprs.push_back(
776 (ast_expression*)ast_return_new(
778 (ast_expression*)ast_binary_new(
781 (ast_expression*)result,
782 (ast_expression*)result
792 body->exprs.push_back(
793 (ast_expression*)ast_ifthen_new(
795 (ast_expression*)ast_binary_new(
798 (ast_expression*)exp,
799 (ast_expression*)intrin->fold->imm_float[1]
801 (ast_expression*)expgt1,
807 * <callsqrt1> = sqrt(base)
809 callsqrt1->params.push_back((ast_expression*)base);
814 * square = sqrt(base);
815 * accumulate = square;
818 body->exprs.push_back(
819 (ast_expression*)ast_store_new(intrin_ctx(intrin),
821 (ast_expression*)low,
822 (ast_expression*)intrin->fold->imm_float[0]
825 body->exprs.push_back(
826 (ast_expression*)ast_store_new(
829 (ast_expression*)high,
830 (ast_expression*)intrin->fold->imm_float[1]
834 body->exprs.push_back(
835 (ast_expression*)ast_store_new(
838 (ast_expression*)square,
839 (ast_expression*)callsqrt1
843 body->exprs.push_back(
844 (ast_expression*)ast_store_new(
847 (ast_expression*)accumulate,
848 (ast_expression*)square
851 body->exprs.push_back(
852 (ast_expression*)ast_store_new(
855 (ast_expression*)mid,
856 (ast_expression*)ast_binary_new(
859 (ast_expression*)high,
860 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
868 * accumulate *= square;
871 midltexp->exprs.push_back(
872 (ast_expression*)ast_store_new(
875 (ast_expression*)low,
879 midltexp->exprs.push_back(
880 (ast_expression*)ast_binstore_new(
884 (ast_expression*)accumulate,
885 (ast_expression*)square
892 * accumulate *= (1.0 / square);
895 midltexpelse->exprs.push_back(
896 (ast_expression*)ast_store_new(
899 (ast_expression*)high,
903 midltexpelse->exprs.push_back(
904 (ast_expression*)ast_binstore_new(
908 (ast_expression*)accumulate,
909 (ast_expression*)ast_binary_new(
912 (ast_expression*)intrin->fold->imm_float[1],
913 (ast_expression*)square
919 * <callsqrt2> = sqrt(square)
921 callsqrt2->params.push_back((ast_expression*)square);
925 * square = <callsqrt2>;
931 * mid = (low + high) / 2;
934 whileblock->exprs.push_back(
935 (ast_expression*)ast_store_new(
938 (ast_expression*)square,
939 (ast_expression*)callsqrt2
942 whileblock->exprs.push_back(
943 (ast_expression*)ast_ifthen_new(
945 (ast_expression*)ast_binary_new(
948 (ast_expression*)mid,
951 (ast_expression*)midltexp,
952 (ast_expression*)midltexpelse
955 whileblock->exprs.push_back(
956 (ast_expression*)ast_store_new(
959 (ast_expression*)mid,
960 (ast_expression*)ast_binary_new(
963 (ast_expression*)ast_binary_new(
966 (ast_expression*)low,
967 (ast_expression*)high
969 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
975 * <callabs> = fabs(mid - exp)
977 callfabs->params.push_back(
978 (ast_expression*)ast_binary_new(
981 (ast_expression*)mid,
987 * while (<callfabs> > epsilon)
990 body->exprs.push_back(
991 (ast_expression*)ast_loop_new(
996 (ast_expression*)ast_binary_new(
999 (ast_expression*)callfabs,
1000 (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON, false)
1004 /* post condition */
1008 /* increment expression */
1011 (ast_expression*)whileblock
1015 /* return accumulate */
1016 body->exprs.push_back(
1017 (ast_expression*)ast_return_new(
1019 (ast_expression*)accumulate
1024 vec_push(func->blocks, body);
1026 intrin_reg(intrin, value, func);
1027 return (ast_expression*)value;
1030 static ast_expression *intrin_mod(intrin_t *intrin) {
1032 * float mod(float a, float b) {
1033 * float div = a / b;
1034 * float sign = (div < 0.0f) ? -1 : 1;
1035 * return a - b * sign * floor(sign * div);
1038 ast_value *value = NULL;
1039 ast_call *call = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "mod"));
1040 ast_value *a = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
1041 ast_value *b = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
1042 ast_value *div = ast_value_new(intrin_ctx(intrin), "div", TYPE_FLOAT);
1043 ast_value *sign = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
1044 ast_block *body = ast_block_new(intrin_ctx(intrin));
1045 ast_function *func = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
1047 value->expression.params.push_back(a);
1048 value->expression.params.push_back(b);
1050 body->locals.push_back(div);
1051 body->locals.push_back(sign);
1054 body->exprs.push_back(
1055 (ast_expression*)ast_store_new(
1058 (ast_expression*)div,
1059 (ast_expression*)ast_binary_new(
1068 /* sign = (div < 0.0f) ? -1 : 1; */
1069 body->exprs.push_back(
1070 (ast_expression*)ast_store_new(
1073 (ast_expression*)sign,
1074 (ast_expression*)ast_ternary_new(
1076 (ast_expression*)ast_binary_new(
1079 (ast_expression*)div,
1080 (ast_expression*)intrin->fold->imm_float[0]
1082 (ast_expression*)intrin->fold->imm_float[2],
1083 (ast_expression*)intrin->fold->imm_float[1]
1088 /* floor(sign * div) */
1089 call->params.push_back(
1090 (ast_expression*)ast_binary_new(
1093 (ast_expression*)sign,
1094 (ast_expression*)div
1098 /* return a - b * sign * <call> */
1099 body->exprs.push_back(
1100 (ast_expression*)ast_return_new(
1102 (ast_expression*)ast_binary_new(
1106 (ast_expression*)ast_binary_new(
1110 (ast_expression*)ast_binary_new(
1113 (ast_expression*)sign,
1114 (ast_expression*)call
1121 vec_push(func->blocks, body);
1122 intrin_reg(intrin, value, func);
1124 return (ast_expression*)value;
1127 static ast_expression *intrin_fabs(intrin_t *intrin) {
1129 * float fabs(float x) {
1130 * return x < 0 ? -x : x;
1133 ast_value *value = NULL;
1134 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1135 ast_block *body = ast_block_new(intrin_ctx(intrin));
1136 ast_function *func = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
1138 body->exprs.push_back(
1139 (ast_expression*)ast_return_new(
1141 (ast_expression*)ast_ternary_new(
1143 (ast_expression*)ast_binary_new(
1146 (ast_expression*)arg1,
1147 (ast_expression*)intrin->fold->imm_float[0]
1149 (ast_expression*)ast_unary_new(
1152 (ast_expression*)arg1
1154 (ast_expression*)arg1
1159 value->expression.params.push_back(arg1);
1161 vec_push(func->blocks, body);
1163 intrin_reg(intrin, value, func);
1165 return (ast_expression*)value;
1168 static ast_expression *intrin_epsilon(intrin_t *intrin) {
1170 * float epsilon(void) {
1172 * do { eps /= 2.0f; } while ((1.0f + (eps / 2.0f)) != 1.0f);
1176 ast_value *value = NULL;
1177 ast_value *eps = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
1178 ast_block *body = ast_block_new(intrin_ctx(intrin));
1179 ast_function *func = intrin_value(intrin, &value, "epsilon", TYPE_FLOAT);
1181 body->locals.push_back(eps);
1184 body->exprs.push_back(
1185 (ast_expression*)ast_store_new(
1188 (ast_expression*)eps,
1189 (ast_expression*)intrin->fold->imm_float[0]
1193 body->exprs.push_back(
1194 (ast_expression*)ast_loop_new(
1199 (ast_expression*)ast_binary_new(
1202 (ast_expression*)ast_binary_new(
1205 (ast_expression*)intrin->fold->imm_float[1],
1206 (ast_expression*)ast_binary_new(
1209 (ast_expression*)eps,
1210 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1213 (ast_expression*)intrin->fold->imm_float[1]
1217 (ast_expression*)ast_binstore_new(
1221 (ast_expression*)eps,
1222 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1228 body->exprs.push_back(
1229 (ast_expression*)ast_return_new(
1231 (ast_expression*)eps
1235 vec_push(func->blocks, body);
1236 intrin_reg(intrin, value, func);
1238 return (ast_expression*)value;
1241 static ast_expression *intrin_nan(intrin_t *intrin) {
1248 ast_value *value = NULL;
1249 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1250 ast_function *func = intrin_value(intrin, &value, "nan", TYPE_FLOAT);
1251 ast_block *block = ast_block_new(intrin_ctx(intrin));
1253 block->locals.push_back(x);
1255 block->exprs.push_back(
1256 (ast_expression*)ast_store_new(
1260 (ast_expression*)intrin->fold->imm_float[0]
1264 block->exprs.push_back(
1265 (ast_expression*)ast_return_new(
1267 (ast_expression*)ast_binary_new(
1276 vec_push(func->blocks, block);
1277 intrin_reg(intrin, value, func);
1279 return (ast_expression*)value;
1282 static ast_expression *intrin_inf(intrin_t *intrin) {
1290 ast_value *value = NULL;
1291 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1292 ast_value *y = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
1293 ast_function *func = intrin_value(intrin, &value, "inf", TYPE_FLOAT);
1294 ast_block *block = ast_block_new(intrin_ctx(intrin));
1297 block->locals.push_back(x);
1298 block->locals.push_back(y);
1300 /* to keep code size down */
1301 for (i = 0; i <= 1; i++) {
1302 block->exprs.push_back(
1303 (ast_expression*)ast_store_new(
1306 (ast_expression*)((i == 0) ? x : y),
1307 (ast_expression*)intrin->fold->imm_float[i]
1312 block->exprs.push_back(
1313 (ast_expression*)ast_return_new(
1315 (ast_expression*)ast_binary_new(
1324 vec_push(func->blocks, block);
1325 intrin_reg(intrin, value, func);
1327 return (ast_expression*)value;
1330 static ast_expression *intrin_ln(intrin_t *intrin) {
1332 * float log(float power, float base) {
1335 * float sign = 1.0f;
1336 * float eps = epsilon();
1338 * if (power <= 1.0f || bbase <= 1.0) {
1339 * if (power <= 0.0f || base <= 0.0f)
1342 * if (power < 1.0f) {
1343 * power = 1.0f / power;
1347 * if (base < 1.0f) {
1349 * base = 1.0f / base;
1355 * float A_iminus1 = 0;
1356 * float B_iminus1 = 1;
1362 * while (whole >= base) {
1363 * float base2 = base;
1365 * float newbase2 = base2 * base2;
1367 * while (whole >= newbase2) {
1370 * newbase2 *= newbase2;
1377 * float b_iplus1 = n;
1378 * float A_iplus1 = b_iplus1 * A_i + A_iminus1;
1379 * float B_iplus1 = b_iplus1 * B_i + B_iminus1;
1386 * if (whole <= 1.0f + eps)
1392 * return sign * A_i / B_i;
1396 ast_value *value = NULL;
1397 ast_value *power = ast_value_new(intrin_ctx(intrin), "power", TYPE_FLOAT);
1398 ast_value *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
1399 ast_value *whole = ast_value_new(intrin_ctx(intrin), "whole", TYPE_FLOAT);
1400 ast_value *nth = ast_value_new(intrin_ctx(intrin), "nth", TYPE_FLOAT);
1401 ast_value *sign = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
1402 ast_value *A_i = ast_value_new(intrin_ctx(intrin), "A_i", TYPE_FLOAT);
1403 ast_value *B_i = ast_value_new(intrin_ctx(intrin), "B_i", TYPE_FLOAT);
1404 ast_value *A_iminus1 = ast_value_new(intrin_ctx(intrin), "A_iminus1", TYPE_FLOAT);
1405 ast_value *B_iminus1 = ast_value_new(intrin_ctx(intrin), "B_iminus1", TYPE_FLOAT);
1406 ast_value *b_iplus1 = ast_value_new(intrin_ctx(intrin), "b_iplus1", TYPE_FLOAT);
1407 ast_value *A_iplus1 = ast_value_new(intrin_ctx(intrin), "A_iplus1", TYPE_FLOAT);
1408 ast_value *B_iplus1 = ast_value_new(intrin_ctx(intrin), "B_iplus1", TYPE_FLOAT);
1409 ast_value *eps = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
1410 ast_value *base2 = ast_value_new(intrin_ctx(intrin), "base2", TYPE_FLOAT);
1411 ast_value *n2 = ast_value_new(intrin_ctx(intrin), "n2", TYPE_FLOAT);
1412 ast_value *newbase2 = ast_value_new(intrin_ctx(intrin), "newbase2", TYPE_FLOAT);
1413 ast_block *block = ast_block_new(intrin_ctx(intrin));
1414 ast_block *plt1orblt1 = ast_block_new(intrin_ctx(intrin)); /* (power <= 1.0f || base <= 1.0f) */
1415 ast_block *plt1 = ast_block_new(intrin_ctx(intrin)); /* (power < 1.0f) */
1416 ast_block *blt1 = ast_block_new(intrin_ctx(intrin)); /* (base < 1.0f) */
1417 ast_block *forloop = ast_block_new(intrin_ctx(intrin)); /* for(;;) */
1418 ast_block *whileloop = ast_block_new(intrin_ctx(intrin)); /* while (whole >= base) */
1419 ast_block *nestwhile = ast_block_new(intrin_ctx(intrin)); /* while (whole >= newbase2) */
1420 ast_function *func = intrin_value(intrin, &value, "ln", TYPE_FLOAT);
1423 value->expression.params.push_back(power);
1424 value->expression.params.push_back(base);
1426 block->locals.push_back(whole);
1427 block->locals.push_back(nth);
1428 block->locals.push_back(sign);
1429 block->locals.push_back(eps);
1430 block->locals.push_back(A_i);
1431 block->locals.push_back(B_i);
1432 block->locals.push_back(A_iminus1);
1433 block->locals.push_back(B_iminus1);
1436 block->exprs.push_back(
1437 (ast_expression*)ast_store_new(
1440 (ast_expression*)sign,
1441 (ast_expression*)intrin->fold->imm_float[1]
1445 /* eps = __builtin_epsilon(); */
1446 block->exprs.push_back(
1447 (ast_expression*)ast_store_new(
1450 (ast_expression*)eps,
1451 (ast_expression*)ast_call_new(
1453 intrin_func_self(intrin, "__builtin_epsilon", "ln")
1464 for (i = 0; i <= 1; i++) {
1466 for (j = 1; j >= 0; j--) {
1467 block->exprs.push_back(
1468 (ast_expression*)ast_store_new(
1471 (ast_expression*)((j) ? ((i) ? B_iminus1 : A_i)
1472 : ((i) ? A_iminus1 : B_i)),
1473 (ast_expression*)intrin->fold->imm_float[j]
1481 * power = 1.0f / power;
1485 * base = 1.0f / base;
1489 for (i = 0; i <= 1; i++) {
1490 ((i) ? blt1 : plt1)->exprs.push_back(
1491 (ast_expression*)ast_store_new(
1494 (ast_expression*)((i) ? base : power),
1495 (ast_expression*)ast_binary_new(
1498 (ast_expression*)intrin->fold->imm_float[1],
1499 (ast_expression*)((i) ? base : power)
1503 plt1->exprs.push_back(
1504 (ast_expression*)ast_binstore_new(
1508 (ast_expression*)sign,
1509 (ast_expression*)intrin->fold->imm_float[2]
1516 * if (power <= 0.0 || base <= 0.0f)
1517 * return __builtin_nan();
1524 plt1orblt1->exprs.push_back(
1525 (ast_expression*)ast_ifthen_new(
1527 (ast_expression*)ast_binary_new(
1530 (ast_expression*)ast_binary_new(
1533 (ast_expression*)power,
1534 (ast_expression*)intrin->fold->imm_float[0]
1536 (ast_expression*)ast_binary_new(
1539 (ast_expression*)base,
1540 (ast_expression*)intrin->fold->imm_float[0]
1543 (ast_expression*)ast_return_new(
1545 (ast_expression*)ast_call_new(
1547 intrin_func_self(intrin, "__builtin_nan", "ln")
1554 for (i = 0; i <= 1; i++) {
1555 plt1orblt1->exprs.push_back(
1556 (ast_expression*)ast_ifthen_new(
1558 (ast_expression*)ast_binary_new(
1561 (ast_expression*)((i) ? base : power),
1562 (ast_expression*)intrin->fold->imm_float[1]
1564 (ast_expression*)((i) ? blt1 : plt1),
1570 block->exprs.push_back((ast_expression*)plt1orblt1);
1573 /* whole = power; */
1574 forloop->exprs.push_back(
1575 (ast_expression*)ast_store_new(
1578 (ast_expression*)whole,
1579 (ast_expression*)power
1584 forloop->exprs.push_back(
1585 (ast_expression*)ast_store_new(
1588 (ast_expression*)nth,
1589 (ast_expression*)intrin->fold->imm_float[0]
1594 whileloop->exprs.push_back(
1595 (ast_expression*)ast_store_new(
1598 (ast_expression*)base2,
1599 (ast_expression*)base
1604 whileloop->exprs.push_back(
1605 (ast_expression*)ast_store_new(
1608 (ast_expression*)n2,
1609 (ast_expression*)intrin->fold->imm_float[1]
1613 /* newbase2 = base2 * base2; */
1614 whileloop->exprs.push_back(
1615 (ast_expression*)ast_store_new(
1618 (ast_expression*)newbase2,
1619 (ast_expression*)ast_binary_new(
1622 (ast_expression*)base2,
1623 (ast_expression*)base2
1628 /* while loop locals */
1629 whileloop->locals.push_back(base2);
1630 whileloop->locals.push_back(n2);
1631 whileloop->locals.push_back(newbase2);
1633 /* base2 = newbase2; */
1634 nestwhile->exprs.push_back(
1635 (ast_expression*)ast_store_new(
1638 (ast_expression*)base2,
1639 (ast_expression*)newbase2
1644 nestwhile->exprs.push_back(
1645 (ast_expression*)ast_binstore_new(
1649 (ast_expression*)n2,
1650 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1654 /* newbase2 *= newbase2; */
1655 nestwhile->exprs.push_back(
1656 (ast_expression*)ast_binstore_new(
1660 (ast_expression*)newbase2,
1661 (ast_expression*)newbase2
1665 /* while (whole >= newbase2) */
1666 whileloop->exprs.push_back(
1667 (ast_expression*)ast_loop_new(
1670 (ast_expression*)ast_binary_new(
1673 (ast_expression*)whole,
1674 (ast_expression*)newbase2
1680 (ast_expression*)nestwhile
1684 /* whole /= base2; */
1685 whileloop->exprs.push_back(
1686 (ast_expression*)ast_binstore_new(
1690 (ast_expression*)whole,
1691 (ast_expression*)base2
1696 whileloop->exprs.push_back(
1697 (ast_expression*)ast_binstore_new(
1701 (ast_expression*)nth,
1706 /* while (whole >= base) */
1707 forloop->exprs.push_back(
1708 (ast_expression*)ast_loop_new(
1711 (ast_expression*)ast_binary_new(
1714 (ast_expression*)whole,
1715 (ast_expression*)base
1721 (ast_expression*)whileloop
1725 forloop->locals.push_back(b_iplus1);
1726 forloop->locals.push_back(A_iplus1);
1727 forloop->locals.push_back(B_iplus1);
1729 /* b_iplus1 = nth; */
1730 forloop->exprs.push_back(
1731 (ast_expression*)ast_store_new(
1734 (ast_expression*)b_iplus1,
1735 (ast_expression*)nth
1740 * A_iplus1 = b_iplus1 * A_i + A_iminus1;
1741 * B_iplus1 = b_iplus1 * B_i + B_iminus1;
1743 for (i = 0; i <= 1; i++) {
1744 forloop->exprs.push_back(
1745 (ast_expression*)ast_store_new(
1748 (ast_expression*)((i) ? B_iplus1 : A_iplus1),
1749 (ast_expression*)ast_binary_new(
1752 (ast_expression*)ast_binary_new(
1755 (ast_expression*)b_iplus1,
1756 (ast_expression*) ((i) ? B_i : A_i)
1758 (ast_expression*)((i) ? B_iminus1 : A_iminus1)
1768 for (i = 0; i <= 1; i++) {
1769 forloop->exprs.push_back(
1770 (ast_expression*)ast_store_new(
1773 (ast_expression*)((i) ? B_iminus1 : A_iminus1),
1774 (ast_expression*)((i) ? B_i : A_i)
1783 for (i = 0; i <= 1; i++) {
1784 forloop->exprs.push_back(
1785 (ast_expression*)ast_store_new(
1788 (ast_expression*)((i) ? B_i : A_i),
1789 (ast_expression*)((i) ? B_iplus1 : A_iplus1)
1795 * if (whole <= 1.0f + eps)
1798 forloop->exprs.push_back(
1799 (ast_expression*)ast_ifthen_new(
1801 (ast_expression*)ast_binary_new(
1804 (ast_expression*)whole,
1805 (ast_expression*)ast_binary_new(
1808 (ast_expression*)intrin->fold->imm_float[1],
1809 (ast_expression*)eps
1812 (ast_expression*)ast_breakcont_new(
1825 for (i = 0; i <= 1; i++) {
1826 forloop->exprs.push_back(
1827 (ast_expression*)ast_store_new(
1830 (ast_expression*)((i) ? base : power),
1831 (ast_expression*)((i) ? whole : base)
1836 /* add the for loop block */
1837 block->exprs.push_back(
1838 (ast_expression*)ast_loop_new(
1841 /* for(; 1; ) ?? (can this be NULL too?) */
1842 (ast_expression*)intrin->fold->imm_float[1],
1847 (ast_expression*)forloop
1851 /* return sign * A_i / B_il */
1852 block->exprs.push_back(
1853 (ast_expression*)ast_return_new(
1855 (ast_expression*)ast_binary_new(
1858 (ast_expression*)sign,
1859 (ast_expression*)ast_binary_new(
1862 (ast_expression*)A_i,
1863 (ast_expression*)B_i
1869 vec_push(func->blocks, block);
1870 intrin_reg(intrin, value, func);
1872 return (ast_expression*)value;
1875 static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) {
1876 ast_value *value = NULL;
1877 ast_call *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", name));
1878 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1879 ast_block *body = ast_block_new(intrin_ctx(intrin));
1880 ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT);
1882 value->expression.params.push_back(arg1);
1884 callln->params.push_back((ast_expression*)arg1);
1885 callln->params.push_back((ast_expression*)fold_constgen_float(intrin->fold, base, false));
1887 body->exprs.push_back(
1888 (ast_expression*)ast_return_new(
1890 (ast_expression*)callln
1894 vec_push(func->blocks, body);
1895 intrin_reg(intrin, value, func);
1896 return (ast_expression*)value;
1899 static ast_expression *intrin_log(intrin_t *intrin) {
1900 return intrin_log_variant(intrin, "log", 2.7182818284590452354);
1902 static ast_expression *intrin_log10(intrin_t *intrin) {
1903 return intrin_log_variant(intrin, "log10", 10);
1905 static ast_expression *intrin_log2(intrin_t *intrin) {
1906 return intrin_log_variant(intrin, "log2", 2);
1908 static ast_expression *intrin_logb(intrin_t *intrin) {
1909 /* FLT_RADIX == 2 for now */
1910 return intrin_log_variant(intrin, "log2", 2);
1913 static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) {
1915 * float [shift] (float a, float b) {
1916 * return floor(a [instr] pow(2, b));
1918 ast_value *value = NULL;
1919 ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
1920 ast_call *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", name));
1921 ast_value *a = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
1922 ast_value *b = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
1923 ast_block *body = ast_block_new(intrin_ctx(intrin));
1924 ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT);
1926 value->expression.params.push_back(a);
1927 value->expression.params.push_back(b);
1929 /* <callpow> = pow(2, b) */
1930 callpow->params.push_back((ast_expression*)intrin->fold->imm_float[3]);
1931 callpow->params.push_back((ast_expression*)b);
1933 /* <callfloor> = floor(a [instr] <callpow>) */
1934 callfloor->params.push_back(
1935 (ast_expression*)ast_binary_new(
1939 (ast_expression*)callpow
1943 /* return <callfloor> */
1944 body->exprs.push_back(
1945 (ast_expression*)ast_return_new(
1947 (ast_expression*)callfloor
1951 vec_push(func->blocks, body);
1952 intrin_reg(intrin, value, func);
1953 return (ast_expression*)value;
1956 static ast_expression *intrin_lshift(intrin_t *intrin) {
1957 return intrin_shift_variant(intrin, "lshift", INSTR_MUL_F);
1960 static ast_expression *intrin_rshift(intrin_t *intrin) {
1961 return intrin_shift_variant(intrin, "rshift", INSTR_DIV_F);
1965 * TODO: make static (and handle ast_type_string) here for the builtin
1966 * instead of in SYA parse close.
1968 ast_expression *intrin_debug_typestring(intrin_t *intrin) {
1970 return (ast_expression*)0x1;
1973 static const intrin_func_t intrinsics[] = {
1974 {&intrin_isfinite, "__builtin_isfinite", "isfinite", 1},
1975 {&intrin_isinf, "__builtin_isinf", "isinf", 1},
1976 {&intrin_isnan, "__builtin_isnan", "isnan", 1},
1977 {&intrin_isnormal, "__builtin_isnormal", "isnormal", 1},
1978 {&intrin_signbit, "__builtin_signbit", "signbit", 1},
1979 {&intrin_acosh, "__builtin_acosh", "acosh", 1},
1980 {&intrin_asinh, "__builtin_asinh", "asinh", 1},
1981 {&intrin_atanh, "__builtin_atanh", "atanh", 1},
1982 {&intrin_exp, "__builtin_exp", "exp", 1},
1983 {&intrin_exp2, "__builtin_exp2", "exp2", 1},
1984 {&intrin_expm1, "__builtin_expm1", "expm1", 1},
1985 {&intrin_mod, "__builtin_mod", "mod", 2},
1986 {&intrin_pow, "__builtin_pow", "pow", 2},
1987 {&intrin_fabs, "__builtin_fabs", "fabs", 1},
1988 {&intrin_log, "__builtin_log", "log", 1},
1989 {&intrin_log10, "__builtin_log10", "log10", 1},
1990 {&intrin_log2, "__builtin_log2", "log2", 1},
1991 {&intrin_logb, "__builtin_logb", "logb", 1},
1992 {&intrin_lshift, "__builtin_lshift", "", 2},
1993 {&intrin_rshift, "__builtin_rshift", "", 2},
1994 {&intrin_epsilon, "__builtin_epsilon", "", 0},
1995 {&intrin_nan, "__builtin_nan", "", 0},
1996 {&intrin_inf, "__builtin_inf", "", 0},
1997 {&intrin_ln, "__builtin_ln", "", 2},
1998 {&intrin_debug_typestring, "__builtin_debug_typestring", "", 0},
1999 {&intrin_nullfunc, "#nullfunc", "", 0}
2002 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
2005 vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
2010 intrin_t *intrin_init(parser_t *parser) {
2011 intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
2014 intrin->parser = parser;
2015 intrin->fold = parser->fold;
2016 intrin->intrinsics = NULL;
2017 intrin->generated = NULL;
2019 vec_append(intrin->intrinsics, GMQCC_ARRAY_COUNT(intrinsics), intrinsics);
2021 /* populate with null pointers for tracking generation */
2022 for (i = 0; i < GMQCC_ARRAY_COUNT(intrinsics); i++)
2023 vec_push(intrin->generated, NULL);
2028 void intrin_cleanup(intrin_t *intrin) {
2029 vec_free(intrin->intrinsics);
2030 vec_free(intrin->generated);
2034 ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
2036 if (!value || !value->name)
2038 for (i = 0; i < vec_size(intrin->intrinsics); i++)
2039 if (!strcmp(value->name, intrin->intrinsics[i].name))
2040 return (vec_size(exprs) != intrin->intrinsics[i].args)
2042 : fold_intrin(intrin->fold, value->name + 10, exprs);
2046 static GMQCC_INLINE ast_expression *intrin_func_try(intrin_t *intrin, size_t offset, const char *compare) {
2048 for (i = 0; i < vec_size(intrin->intrinsics); i++) {
2049 if (strcmp(*(char **)((char *)&intrin->intrinsics[i] + offset), compare))
2051 if (intrin->generated[i])
2052 return intrin->generated[i];
2053 return intrin->generated[i] = intrin->intrinsics[i].intrin(intrin);
2058 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
2059 ast_expression *find;
2060 /* try current first */
2061 if ((find = parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
2062 for (auto &it : intrin->parser->functions)
2063 if (((ast_value*)find)->name && !strcmp(it->name, ((ast_value*)find)->name) && it->builtin < 0)
2065 /* try name second */
2066 if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, name), name)))
2068 /* try alias third */
2069 if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
2073 intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
2074 return intrin_func_self(intrin, "#nullfunc", NULL);
2079 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
2080 return intrin_func_self(intrin, name, NULL);