* is entered when -fintrin is used (causing all existing builtins to
* be ignored by the compiler and instead interface through here.
*/
-#define INTRIN_VAL(VALUE, NAME, FUNC, STYPE, VTYPE) \
- do { \
- (VALUE) = ast_value_new ( \
- parser_ctx(intrin->parser), \
- "__builtin_" NAME, \
- TYPE_FUNCTION \
- ); \
- (VALUE)->intrinsic = true; \
- (VALUE)->expression.next = (ast_expression*)ast_value_new ( \
- parser_ctx(intrin->parser), \
- STYPE, \
- VTYPE \
- ); \
- (FUNC) = ast_function_new ( \
- parser_ctx(intrin->parser), \
- "__builtin_" NAME, \
- (VALUE) \
- ); \
- } while (0)
-
-#define INTRIN_REG(FUNC, VALUE) \
- do { \
- vec_push(intrin->parser->functions, (FUNC)); \
- vec_push(intrin->parser->globals, (ast_expression*)(VALUE)); \
- } while (0)
+#define intrin_ctx(I) parser_ctx((I)->parser)
+
+static GMQCC_INLINE ast_function *intrin_value(intrin_t *intrin, ast_value **value, const char *name, qcint_t vtype) {
+ ast_function *func = NULL;
+ char buffer[1024];
+ char stype [1024];
+
+ util_snprintf(buffer, sizeof(buffer), "__builtin_%s", name);
+ util_snprintf(stype, sizeof(stype), "<%s>", type_name[vtype]);
+
+ *value = ast_value_new(intrin_ctx(intrin), buffer, TYPE_FUNCTION);
+ (*value)->intrinsic = true;
+ (*value)->expression.next = (ast_expression*)ast_value_new(intrin_ctx(intrin), stype, vtype);
+ func = ast_function_new(intrin_ctx(intrin), buffer, *value);
+ (*value)->expression.flags |= AST_FLAG_ERASEABLE;
+
+ return func;
+}
+
+static GMQCC_INLINE void intrin_reg(intrin_t *intrin, ast_value *const value, ast_function *const func) {
+ vec_push(intrin->parser->functions, func);
+ vec_push(intrin->parser->globals, (ast_expression*)value);
+}
#define QC_M_E 2.71828182845905f
ast_block *l2b = ast_block_new(parser_ctx(intrin->parser)); /* loop 2 body */
ast_loop *loop1 = NULL;
ast_loop *loop2 = NULL;
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "pow", func, "<float>", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
/* arguments */
vec_push(value->expression.params, arg1);
/* push block and register intrin for codegen */
vec_push(func->blocks, body);
- INTRIN_REG(func, value);
+ intrin_reg(intrin, value, func);
}
return (ast_expression*)value;
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_value *arg2 = ast_value_new(parser_ctx(intrin->parser), "y", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "mod", func, "<float>", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
/* floor(x/y) */
vec_push(call->params,
vec_push(func->blocks, body); /* {{{ body }}} */
- INTRIN_REG(func, value);
+ intrin_reg(intrin, value, func);
}
return (ast_expression*)value;
ast_call *call = ast_call_new (parser_ctx(intrin->parser), intrin_func(intrin, "pow"));
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "exp", func, "<float>", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "exp", TYPE_FLOAT);
/* push arguments for params to call */
vec_push(call->params, (ast_expression*)fold_constgen_float(intrin->fold, QC_M_E));
vec_push(func->blocks, body); /* {{{ body }}} */
- INTRIN_REG(func, value);
+ intrin_reg(intrin, value, func);
}
return (ast_expression*)value;
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_value *local = ast_value_new(parser_ctx(intrin->parser), "local", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "isnan", func, "<float>", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
vec_push(body->locals, local);
vec_push(body->exprs,
vec_push(value->expression.params, arg1);
vec_push(func->blocks, body);
- INTRIN_REG(func, value);
+ intrin_reg(intrin, value, func);
}
return (ast_expression*)value;
if (!value) {
ast_value *arg1 = ast_value_new(parser_ctx(intrin->parser), "x", TYPE_FLOAT);
ast_block *body = ast_block_new(parser_ctx(intrin->parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "fabs", func, "<float>", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
vec_push(body->exprs,
(ast_expression*)ast_return_new(
vec_push(value->expression.params, arg1);
vec_push(func->blocks, body);
- INTRIN_REG(func, value);
+ intrin_reg(intrin, value, func);
}
return (ast_expression*)value;
}
-#undef INTRIN_REG
-#undef INTRIN_VAL
-
/*
* TODO: make static (and handle ast_type_string) here for the builtin
* instead of in SYA parse close.
}
static const intrin_func_t intrinsics[] = {
- {&intrin_exp, "__builtin_exp", "exp"},
- {&intrin_mod, "__builtin_mod", "mod"},
- {&intrin_pow, "__builtin_pow", "pow"},
- {&intrin_isnan, "__builtin_isnan", "isnan"},
- {&intrin_fabs, "__builtin_fabs", "fabs"},
- {&intrin_debug_typestring, "__builtin_debug_typestring", ""}
+ {&intrin_exp, "__builtin_exp", "exp", 1},
+ {&intrin_mod, "__builtin_mod", "mod", 2},
+ {&intrin_pow, "__builtin_pow", "pow", 2},
+ {&intrin_isnan, "__builtin_isnan", "isnan", 1},
+ {&intrin_fabs, "__builtin_fabs", "fabs", 1},
+ {&intrin_debug_typestring, "__builtin_debug_typestring", "", 0}
};
static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
if (!value || !value->name)
return NULL;
- for (i = 0; i < vec_size(intrin->intrinsics); i++)
- if (!strcmp(value->name, intrin->intrinsics[i].name))
- return fold_intrin(intrin->fold, value->name, exprs);
+ for (i = 0; i < vec_size(intrin->intrinsics); i++) {
+ if (!strcmp(value->name, intrin->intrinsics[i].name)) {
+ if (intrin->intrinsics[i].args != vec_size(exprs))
+ return NULL;
+ /* +10 to skip the "__builtin_" substring in the string */
+ return fold_intrin(intrin->fold, value->name + 10, exprs);
+ }
+ }
return NULL;
}