2 * Copyright (C) 2012, 2013
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Provides all the "intrinsics" / "builtins" for GMQCC. These can do
28 * a few things, they can provide fall back implementations for math
29 * functions if the definitions don't exist for some given engine. Or
30 * then can determine definitions for existing builtins, and simply
31 * wrap back to them instead. This is like a "portable" intrface that
32 * is entered when -fintrin is used (causing all existing builtins to
33 * be ignored by the compiler and instead interface through here.
35 #define intrin_ctx(I) parser_ctx((I)->parser)
37 static GMQCC_INLINE ast_function *intrin_value(intrin_t *intrin, ast_value **out, const char *name, qcint_t vtype) {
38 ast_value *value = NULL;
39 ast_function *func = NULL;
43 util_snprintf(buffer, sizeof(buffer), "__builtin_%s", name);
44 util_snprintf(stype, sizeof(stype), "<%s>", type_name[vtype]);
46 value = ast_value_new(intrin_ctx(intrin), buffer, TYPE_FUNCTION);
47 value->intrinsic = true;
48 value->expression.next = (ast_expression*)ast_value_new(intrin_ctx(intrin), stype, vtype);
49 func = ast_function_new(intrin_ctx(intrin), buffer, value);
50 value->expression.flags |= AST_FLAG_ERASEABLE;
56 static GMQCC_INLINE void intrin_reg(intrin_t *intrin, ast_value *const value, ast_function *const func) {
57 vec_push(intrin->parser->functions, func);
58 vec_push(intrin->parser->globals, (ast_expression*)value);
61 #define QC_POW_EPSILON 0.00001f
64 * since some intrinsics depend on each other there is the possibility
65 * that an intrinsic will fail to get a 'depended' function that a
66 * builtin needs, causing some dependency in the chain to have a NULL
67 * function. This will cause a segmentation fault at code generation,
68 * even though an error was raised. To contiue to allow it (instead
69 * of stopping compilation right away). We need to return from the
70 * parser, before compilation stops after all the collected errors.
72 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from);
73 static ast_expression *intrin_nullfunc(intrin_t *intrin) {
74 ast_value *value = NULL;
75 ast_function *func = intrin_value(intrin, &value, NULL, TYPE_VOID);
76 intrin_reg(intrin, value, func);
77 return (ast_expression*)value;
80 static ast_expression *intrin_pow(intrin_t *intrin) {
83 * float pow(float base, float exp) {
96 * return 1.0 / pow(base, -exp);
98 * result = pow(base, exp / 2);
99 * return result * result;
104 * square = sqrt(base);
105 * accumulate = square;
108 * while (fabs(mid - exp) > QC_POW_EPSILON) {
109 * square = sqrt(square);
112 * accumulate *= square;
115 * accumulate *= (1.0f / square);
117 * mid = (low + high) / 2;
122 ast_value *value = NULL;
123 ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
125 /* prepare some calls for later */
126 ast_call *callpow1 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(base, -exp) */
127 ast_call *callpow2 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(vase, exp / 2) */
128 ast_call *callsqrt1 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(base) */
129 ast_call *callsqrt2 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(square) */
130 ast_call *callfabs = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "fabs", "pow")); /* for fabs(mid - exp) */
132 /* prepare some blocks for later */
133 ast_block *expgt1 = ast_block_new(intrin_ctx(intrin));
134 ast_block *midltexp = ast_block_new(intrin_ctx(intrin));
135 ast_block *midltexpelse = ast_block_new(intrin_ctx(intrin));
136 ast_block *whileblock = ast_block_new(intrin_ctx(intrin));
138 /* float pow(float base, float exp) */
139 ast_value *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
140 ast_value *exp = ast_value_new(intrin_ctx(intrin), "exp", TYPE_FLOAT);
142 ast_block *body = ast_block_new(intrin_ctx(intrin));
152 ast_value *result = ast_value_new(intrin_ctx(intrin), "result", TYPE_FLOAT);
153 ast_value *low = ast_value_new(intrin_ctx(intrin), "low", TYPE_FLOAT);
154 ast_value *high = ast_value_new(intrin_ctx(intrin), "high", TYPE_FLOAT);
155 ast_value *square = ast_value_new(intrin_ctx(intrin), "square", TYPE_FLOAT);
156 ast_value *accumulate = ast_value_new(intrin_ctx(intrin), "accumulate", TYPE_FLOAT);
157 ast_value *mid = ast_value_new(intrin_ctx(intrin), "mid", TYPE_FLOAT);
158 vec_push(body->locals, result);
159 vec_push(body->locals, low);
160 vec_push(body->locals, high);
161 vec_push(body->locals, square);
162 vec_push(body->locals, accumulate);
163 vec_push(body->locals, mid);
165 vec_push(value->expression.params, base);
166 vec_push(value->expression.params, exp);
172 vec_push(body->exprs,
173 (ast_expression*)ast_ifthen_new(
175 (ast_expression*)ast_binary_new(
178 (ast_expression*)exp,
179 (ast_expression*)intrin->fold->imm_float[0]
181 (ast_expression*)ast_return_new(
183 (ast_expression*)intrin->fold->imm_float[1]
193 vec_push(body->exprs,
194 (ast_expression*)ast_ifthen_new(
196 (ast_expression*)ast_binary_new(
199 (ast_expression*)exp,
200 (ast_expression*)intrin->fold->imm_float[1]
202 (ast_expression*)ast_return_new(
204 (ast_expression*)base
210 /* <callpow1> = pow(base, -exp) */
211 vec_push(callpow1->params, (ast_expression*)base);
212 vec_push(callpow1->params,
213 (ast_expression*)ast_unary_new(
222 * return 1.0 / <callpow1>;
224 vec_push(body->exprs,
225 (ast_expression*)ast_ifthen_new(
227 (ast_expression*)ast_binary_new(
230 (ast_expression*)exp,
231 (ast_expression*)intrin->fold->imm_float[0]
233 (ast_expression*)ast_return_new(
235 (ast_expression*)ast_binary_new(
238 (ast_expression*)intrin->fold->imm_float[1],
239 (ast_expression*)callpow1
246 /* <callpow2> = pow(base, exp / 2) */
247 vec_push(callpow2->params, (ast_expression*)base);
248 vec_push(callpow2->params,
249 (ast_expression*)ast_binary_new(
252 (ast_expression*)exp,
253 (ast_expression*)fold_constgen_float(intrin->fold, 2.0f)
259 * result = <callpow2>;
260 * return result * result;
263 vec_push(expgt1->exprs,
264 (ast_expression*)ast_store_new(
267 (ast_expression*)result,
268 (ast_expression*)callpow2
271 vec_push(expgt1->exprs,
272 (ast_expression*)ast_return_new(
274 (ast_expression*)ast_binary_new(
277 (ast_expression*)result,
278 (ast_expression*)result
288 vec_push(body->exprs,
289 (ast_expression*)ast_ifthen_new(
291 (ast_expression*)ast_binary_new(
294 (ast_expression*)exp,
295 (ast_expression*)intrin->fold->imm_float[1]
297 (ast_expression*)expgt1,
303 * <callsqrt1> = sqrt(base)
305 vec_push(callsqrt1->params, (ast_expression*)base);
310 * square = sqrt(base);
311 * accumulate = square;
314 vec_push(body->exprs,
315 (ast_expression*)ast_store_new(intrin_ctx(intrin),
317 (ast_expression*)low,
318 (ast_expression*)intrin->fold->imm_float[0]
321 vec_push(body->exprs,
322 (ast_expression*)ast_store_new(
325 (ast_expression*)high,
326 (ast_expression*)intrin->fold->imm_float[1]
329 vec_push(body->exprs,
330 (ast_expression*)ast_store_new(
333 (ast_expression*)square,
334 (ast_expression*)callsqrt1
337 vec_push(body->exprs,
338 (ast_expression*)ast_store_new(
341 (ast_expression*)accumulate,
342 (ast_expression*)square
345 vec_push(body->exprs,
346 (ast_expression*)ast_store_new(
349 (ast_expression*)mid,
350 (ast_expression*)ast_binary_new(
353 (ast_expression*)high,
354 (ast_expression*)fold_constgen_float(intrin->fold, 2.0f)
362 * accumulate *= square;
365 vec_push(midltexp->exprs,
366 (ast_expression*)ast_store_new(
369 (ast_expression*)low,
373 vec_push(midltexp->exprs,
374 (ast_expression*)ast_binstore_new(
378 (ast_expression*)accumulate,
379 (ast_expression*)square
386 * accumulate *= (1.0 / square);
389 vec_push(midltexpelse->exprs,
390 (ast_expression*)ast_store_new(
393 (ast_expression*)high,
397 vec_push(midltexpelse->exprs,
398 (ast_expression*)ast_binstore_new(
402 (ast_expression*)accumulate,
403 (ast_expression*)ast_binary_new(
406 (ast_expression*)intrin->fold->imm_float[1],
407 (ast_expression*)square
413 * <callsqrt2> = sqrt(square)
415 vec_push(callsqrt2->params, (ast_expression*)square);
419 * square = <callsqrt2>;
425 * mid = (low + high) / 2;
428 vec_push(whileblock->exprs,
429 (ast_expression*)ast_store_new(
432 (ast_expression*)square,
433 (ast_expression*)callsqrt2
436 vec_push(whileblock->exprs,
437 (ast_expression*)ast_ifthen_new(
439 (ast_expression*)ast_binary_new(
442 (ast_expression*)mid,
445 (ast_expression*)midltexp,
446 (ast_expression*)midltexpelse
449 vec_push(whileblock->exprs,
450 (ast_expression*)ast_store_new(
453 (ast_expression*)mid,
454 (ast_expression*)ast_binary_new(
457 (ast_expression*)ast_binary_new(
460 (ast_expression*)low,
461 (ast_expression*)high
463 (ast_expression*)fold_constgen_float(intrin->fold, 2.0f)
469 * <callabs> = fabs(mid - exp)
471 vec_push(callfabs->params,
472 (ast_expression*)ast_binary_new(
475 (ast_expression*)mid,
481 * while (<callfabs> > epsilon)
484 vec_push(body->exprs,
485 (ast_expression*)ast_loop_new(
490 (ast_expression*)ast_binary_new(
493 (ast_expression*)callfabs,
494 (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON)
502 /* increment expression */
505 (ast_expression*)whileblock
509 /* return accumulate */
510 vec_push(body->exprs,
511 (ast_expression*)ast_return_new(
513 (ast_expression*)accumulate
518 vec_push(func->blocks, body);
520 intrin_reg(intrin, value, func);
521 return (ast_expression*)value;
524 static ast_expression *intrin_mod(intrin_t *intrin) {
526 * float mod(float a, float b) {
528 * float sign = (div < 0.0f) ? -1 : 1;
529 * return a - b * sign * floor(sign * div);
532 ast_value *value = NULL;
533 ast_call *call = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "mod"));
534 ast_value *a = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
535 ast_value *b = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
536 ast_value *div = ast_value_new(intrin_ctx(intrin), "div", TYPE_FLOAT);
537 ast_value *sign = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
538 ast_block *body = ast_block_new(intrin_ctx(intrin));
539 ast_function *func = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
541 vec_push(value->expression.params, a);
542 vec_push(value->expression.params, b);
544 vec_push(body->locals, div);
545 vec_push(body->locals, sign);
548 vec_push(body->exprs,
549 (ast_expression*)ast_store_new(
552 (ast_expression*)div,
553 (ast_expression*)ast_binary_new(
562 /* sign = (div < 0.0f) ? -1 : 1; */
563 vec_push(body->exprs,
564 (ast_expression*)ast_store_new(
567 (ast_expression*)sign,
568 (ast_expression*)ast_ternary_new(
570 (ast_expression*)ast_binary_new(
573 (ast_expression*)div,
574 (ast_expression*)intrin->fold->imm_float[0]
576 (ast_expression*)intrin->fold->imm_float[2],
577 (ast_expression*)intrin->fold->imm_float[1]
582 /* floor(sign * div) */
583 vec_push(call->params,
584 (ast_expression*)ast_binary_new(
587 (ast_expression*)sign,
592 /* return a - b * sign * <call> */
593 vec_push(body->exprs,
594 (ast_expression*)ast_return_new(
596 (ast_expression*)ast_binary_new(
600 (ast_expression*)ast_binary_new(
604 (ast_expression*)ast_binary_new(
607 (ast_expression*)sign,
608 (ast_expression*)call
615 vec_push(func->blocks, body); /* {{{ body }}} */
616 intrin_reg(intrin, value, func);
618 return (ast_expression*)value;
621 static ast_expression *intrin_exp(intrin_t *intrin) {
623 * float exp(float x) {
627 * for (i = 1; i < 200; ++i)
628 * sum += (acc *= x / i);
633 ast_value *value = NULL;
634 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
635 ast_value *sum = ast_value_new(intrin_ctx(intrin), "sum", TYPE_FLOAT);
636 ast_value *acc = ast_value_new(intrin_ctx(intrin), "acc", TYPE_FLOAT);
637 ast_value *i = ast_value_new(intrin_ctx(intrin), "i", TYPE_FLOAT);
638 ast_block *body = ast_block_new(intrin_ctx(intrin));
639 ast_function *func = intrin_value(intrin, &value, "mexp", TYPE_FLOAT);
641 vec_push(value->expression.params, x);
642 vec_push(body->locals, sum);
643 vec_push(body->locals, acc);
644 vec_push(body->locals, i);
647 vec_push(body->exprs,
648 (ast_expression*)ast_store_new(
651 (ast_expression*)sum,
652 (ast_expression*)intrin->fold->imm_float[1]
657 vec_push(body->exprs,
658 (ast_expression*)ast_store_new(
661 (ast_expression*)acc,
662 (ast_expression*)intrin->fold->imm_float[1]
667 * for (i = 1; i < 200; ++i)
668 * sum += (acc *= x / i);
670 vec_push(body->exprs,
671 (ast_expression*)ast_loop_new(
674 (ast_expression*)ast_store_new(
678 (ast_expression*)intrin->fold->imm_float[1]
681 (ast_expression*)ast_binary_new(
685 (ast_expression*)fold_constgen_float(intrin->fold, 200.0f)
691 (ast_expression*)ast_binstore_new(
696 (ast_expression*)intrin->fold->imm_float[1]
698 /* sum += (acc *= (x / i)) */
699 (ast_expression*)ast_binstore_new(
703 (ast_expression*)sum,
704 (ast_expression*)ast_binstore_new(
708 (ast_expression*)acc,
709 (ast_expression*)ast_binary_new(
721 vec_push(body->exprs,
722 (ast_expression*)ast_return_new(
728 vec_push(func->blocks, body); /* {{{ body }}} */
730 intrin_reg(intrin, value, func);
731 return (ast_expression*)value;
734 static ast_expression *intrin_exp2(intrin_t *intrin) {
736 * float exp2(float x) {
740 ast_value *value = NULL;
741 ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp2"));
742 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
743 ast_block *body = ast_block_new(intrin_ctx(intrin));
744 ast_function *func = intrin_value(intrin, &value, "exp2", TYPE_FLOAT);
746 vec_push(value->expression.params, arg1);
748 vec_push(callpow->params, (ast_expression*)fold_constgen_float(intrin->fold, 2.0f));
749 vec_push(callpow->params, (ast_expression*)arg1);
751 /* return <callpow> */
752 vec_push(body->exprs,
753 (ast_expression*)ast_return_new(
755 (ast_expression*)callpow
759 vec_push(func->blocks, body);
761 intrin_reg(intrin, value, func);
762 return (ast_expression*)value;
765 static ast_expression *intrin_isinf(intrin_t *intrin) {
767 * float isinf(float x) {
768 * return (x != 0.0) && (x + x == x);
771 ast_value *value = NULL;
772 ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
773 ast_block *body = ast_block_new(intrin_ctx(intrin));
774 ast_function *func = intrin_value(intrin, &value, "isinf", TYPE_FLOAT);
776 vec_push(body->exprs,
777 (ast_expression*)ast_return_new(
779 (ast_expression*)ast_binary_new(
782 (ast_expression*)ast_binary_new(
786 (ast_expression*)intrin->fold->imm_float[0]
788 (ast_expression*)ast_binary_new(
791 (ast_expression*)ast_binary_new(
803 vec_push(value->expression.params, x);
804 vec_push(func->blocks, body);
806 intrin_reg(intrin, value, func);
808 return (ast_expression*)value;
811 static ast_expression *intrin_isnan(intrin_t *intrin) {
813 * float isnan(float x) {
817 * return (x != local);
820 ast_value *value = NULL;
821 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
822 ast_value *local = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
823 ast_block *body = ast_block_new(intrin_ctx(intrin));
824 ast_function *func = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
826 vec_push(body->locals, local);
827 vec_push(body->exprs,
828 (ast_expression*)ast_store_new(
831 (ast_expression*)local,
832 (ast_expression*)arg1
836 vec_push(body->exprs,
837 (ast_expression*)ast_return_new(
839 (ast_expression*)ast_binary_new(
842 (ast_expression*)arg1,
843 (ast_expression*)local
848 vec_push(value->expression.params, arg1);
849 vec_push(func->blocks, body);
851 intrin_reg(intrin, value, func);
853 return (ast_expression*)value;
856 static ast_expression *intrin_fabs(intrin_t *intrin) {
858 * float fabs(float x) {
859 * return x < 0 ? -x : x;
862 ast_value *value = NULL;
863 ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
864 ast_block *body = ast_block_new(intrin_ctx(intrin));
865 ast_function *func = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
867 vec_push(body->exprs,
868 (ast_expression*)ast_return_new(
870 (ast_expression*)ast_ternary_new(
872 (ast_expression*)ast_binary_new(
875 (ast_expression*)arg1,
876 (ast_expression*)intrin->fold->imm_float[0]
878 (ast_expression*)ast_unary_new(
881 (ast_expression*)arg1
883 (ast_expression*)arg1
888 vec_push(value->expression.params, arg1);
889 vec_push(func->blocks, body);
891 intrin_reg(intrin, value, func);
893 return (ast_expression*)value;
897 * TODO: make static (and handle ast_type_string) here for the builtin
898 * instead of in SYA parse close.
900 ast_expression *intrin_debug_typestring(intrin_t *intrin) {
902 return (ast_expression*)0x1;
905 static const intrin_func_t intrinsics[] = {
906 {&intrin_exp, "__builtin_exp", "exp", 1},
907 {&intrin_exp2, "__builtin_exp2", "exp2", 1},
908 {&intrin_mod, "__builtin_mod", "mod", 2},
909 {&intrin_pow, "__builtin_pow", "pow", 2},
910 {&intrin_isnan, "__builtin_isnan", "isnan", 1},
911 {&intrin_isinf, "__builtin_isinf", "isinf", 1},
912 {&intrin_fabs, "__builtin_fabs", "fabs", 1},
913 {&intrin_debug_typestring, "__builtin_debug_typestring", "", 0},
914 {&intrin_nullfunc, "#nullfunc", "", 0}
917 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
920 vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
925 intrin_t *intrin_init(parser_t *parser) {
926 intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
929 intrin->parser = parser;
930 intrin->fold = parser->fold;
931 intrin->intrinsics = NULL;
932 intrin->generated = NULL;
934 vec_append(intrin->intrinsics, GMQCC_ARRAY_COUNT(intrinsics), intrinsics);
936 /* populate with null pointers for tracking generation */
937 for (i = 0; i < GMQCC_ARRAY_COUNT(intrinsics); i++)
938 vec_push(intrin->generated, NULL);
943 void intrin_cleanup(intrin_t *intrin) {
944 vec_free(intrin->intrinsics);
945 vec_free(intrin->generated);
949 ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
951 if (!value || !value->name)
953 for (i = 0; i < vec_size(intrin->intrinsics); i++)
954 if (!strcmp(value->name, intrin->intrinsics[i].name))
955 return (vec_size(exprs) != intrin->intrinsics[i].args)
957 : fold_intrin(intrin->fold, value->name + 10, exprs);
961 static GMQCC_INLINE ast_expression *intrin_func_try(intrin_t *intrin, size_t offset, const char *compare) {
963 for (i = 0; i < vec_size(intrin->intrinsics); i++) {
964 if (strcmp(*(char **)((char *)&intrin->intrinsics[i] + offset), compare))
966 if (intrin->generated[i])
967 return intrin->generated[i];
968 return intrin->generated[i] = intrin->intrinsics[i].intrin(intrin);
973 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
975 ast_expression *find;
977 /* try current first */
978 if ((find = parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
979 for (i = 0; i < vec_size(intrin->parser->functions); ++i)
980 if (((ast_value*)find)->name && !strcmp(intrin->parser->functions[i]->name, ((ast_value*)find)->name) && intrin->parser->functions[i]->builtin < 0)
982 /* try name second */
983 if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, name), name)))
985 /* try alias third */
986 if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
990 intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
991 return intrin_func_self(intrin, "#nullfunc", NULL);
996 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
997 return intrin_func_self(intrin, name, NULL);