"__builtin_" NAME, \
TYPE_FUNCTION \
); \
+ (VALUE)->intrinsic = true; \
(VALUE)->expression.next = (ast_expression*)ast_value_new ( \
parser_ctx(intrin->parser), \
STYPE, \
"__builtin_" NAME, \
(VALUE) \
); \
+ (VALUE)->expression.flags |= AST_FLAG_ERASEABLE; \
} while (0)
#define INTRIN_REG(FUNC, VALUE) \
return (ast_expression*)value;
}
+
+static ast_expression *intrin_fabs(intrin_t *intrin) {
+ /*
+ * float fabs(float x) {
+ * return x < 0 ? -x : x;
+ * }
+ */
+ static ast_value *value = NULL;
+ 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);
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ parser_ctx(intrin->parser),
+ (ast_expression*)ast_ternary_new(
+ parser_ctx(intrin->parser),
+ (ast_expression*)ast_binary_new(
+ parser_ctx(intrin->parser),
+ INSTR_LE,
+ (ast_expression*)arg1,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_binary_new(
+ parser_ctx(intrin->parser),
+ INSTR_SUB_F,
+ (ast_expression*)intrin->fold->imm_float[0],
+ (ast_expression*)arg1
+ ),
+ (ast_expression*)arg1
+ )
+ )
+ );
+
+ vec_push(value->expression.params, arg1);
+ vec_push(func->blocks, body);
+
+ INTRIN_REG(func, value);
+ }
+
+ return (ast_expression*)value;
+}
+
#undef INTRIN_REG
#undef INTRIN_VAL
}
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_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, ...) {
mem_d(intrin);
}
+ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
+ size_t i;
+
+ if (!value || !value->name)
+ return NULL;
+
+ 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)) {
+ intrin_error(
+ intrin,
+ "internal error: attempted to constant-fold with invalid paramaters for intrinsic `%s`\n"
+ " ==> expected %u arguments, got %u instead",
+ value->name, 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;
+}
+
ast_expression *intrin_func(intrin_t *intrin, const char *name) {
size_t i = 0;
void *find;