-#define INTRIN_VAL(VALUE, NAME, FUNC, STYPE, VTYPE) \
- do { \
- (VALUE) = ast_value_new ( \
- parser_ctx(parser), \
- "__builtin_" NAME, \
- TYPE_FUNCTION \
- ); \
- (VALUE)->expression.next = (ast_expression*)ast_value_new ( \
- parser_ctx(parser), \
- STYPE, \
- VTYPE \
- ); \
- (FUNC) = ast_function_new ( \
- parser_ctx(parser), \
- "__builtin_" NAME, \
- (VALUE) \
- ); \
- } while (0)
-
-#define INTRIN_REG(FUNC, VALUE) \
- do { \
- vec_push(parser->functions, (FUNC)); \
- vec_push(parser->globals, (ast_expression*)(VALUE)); \
- } while (0)
-
-
-ast_expression *intrin_func (parser_t *parser, const char *name);
-
-#define QC_M_E 2.71828182845905
-
-ast_expression *intrin_pow(parser_t *parser) {
- /*
- * float pow(float x, float y) {
- * float local = 1.0f;
- * while (y > 0) {
- * while (!(y & 1)) {
- * y >>= 2;
- * x *= x;
- * }
- * y--;
- * local *= x;
- * }
- * return local;
- * }
- */
- static ast_value *value = NULL;
-
- if (!value) {
- ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
- ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
- ast_value *local = ast_value_new(parser_ctx(parser), "local", TYPE_FLOAT);
- ast_block *body = ast_block_new(parser_ctx(parser));
- ast_block *l1b = ast_block_new(parser_ctx(parser)); /* loop 1 body */
- ast_block *l2b = ast_block_new(parser_ctx(parser)); /* looo 2 body */
- ast_loop *loop1 = NULL;
- ast_loop *loop2 = NULL;
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "pow", func, "<float>", TYPE_FLOAT);
-
- /* arguments */
- vec_push(value->expression.params, arg1);
- vec_push(value->expression.params, arg2);
-
- /* local */
- vec_push(body->locals, local);
-
- /* assignment to local of value 1.0f */
- vec_push(body->exprs,
- (ast_expression*)ast_store_new (
- parser_ctx(parser),
- INSTR_STORE_F,
- (ast_expression*)local,
- (ast_expression*)parser_const_float_1(parser)
- )
- );
-
- /* y >>= 2 */
- vec_push(l2b->exprs,
- (ast_expression*)ast_binstore_new (
- parser_ctx(parser),
- INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)arg2,
- (ast_expression*)parser_const_float(parser, 0.25f)
- )
- );
-
- /* x *= x */
- vec_push(l2b->exprs,
- (ast_expression*)ast_binstore_new (
- parser_ctx(parser),
- INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)arg1,
- (ast_expression*)arg1
- )
- );
-
- /* while (!(y&1)) */
- loop2 = ast_loop_new (
- parser_ctx(parser),
- NULL,
- (ast_expression*)ast_binary_new (
- parser_ctx(parser),
- INSTR_AND,
- (ast_expression*)arg2,
- (ast_expression*)parser_const_float_1(parser)
- ),
- true, /* ! not */
- NULL,
- false,
- NULL,
- (ast_expression*)l2b
- );
-
- /* push nested loop into loop expressions */
- vec_push(l1b->exprs, (ast_expression*)loop2);
-
- /* y-- */
- vec_push(l1b->exprs,
- (ast_expression*)ast_binstore_new (
- parser_ctx(parser),
- INSTR_STORE_F,
- INSTR_SUB_F,
- (ast_expression*)arg2,
- (ast_expression*)parser_const_float_1(parser)
- )
- );
- /* local *= x */
- vec_push(l1b->exprs,
- (ast_expression*)ast_binstore_new (
- parser_ctx(parser),
- INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)local,
- (ast_expression*)arg1
- )
- );
-
- /* while (y > 0) */
- loop1 = ast_loop_new (
- parser_ctx(parser),
- NULL,
- (ast_expression*)ast_binary_new (
- parser_ctx(parser),
- INSTR_GT,
- (ast_expression*)arg2,
- (ast_expression*)parser_const_float_0(parser)
- ),
- false,
- NULL,
- false,
- NULL,
- (ast_expression*)l1b
- );
-
- /* push the loop1 into the body for the function */
- vec_push(body->exprs, (ast_expression*)loop1);
-
- /* return local; */
- vec_push(body->exprs,
- (ast_expression*)ast_return_new (
- parser_ctx(parser),
- (ast_expression*)local
- )
- );
-
- /* push block and register intrin for codegen */
- vec_push(func->blocks, body);
-
- INTRIN_REG(func, value);
- }
-
- return (ast_expression*)value;
-}
-
-ast_expression *intrin_mod(parser_t *parser) {
- /*
- * float mod(float x, float y) {
- * return x - y * floor(x / y);
- * }
- */
- static ast_value *value = NULL;
-
- if (!value) {
- ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "floor"));
- ast_value *arg1 = ast_value_new(parser_ctx(parser), "x", TYPE_FLOAT);
- ast_value *arg2 = ast_value_new(parser_ctx(parser), "y", TYPE_FLOAT);
- ast_block *body = ast_block_new(parser_ctx(parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "mod", func, "<float>", TYPE_FLOAT);
-
- /* floor(x/y) */
- vec_push(call->params,
- (ast_expression*)ast_binary_new (
- parser_ctx(parser),
- INSTR_DIV_F,
- (ast_expression*)arg1,
- (ast_expression*)arg2
- )
- );
-
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
- parser_ctx(parser),
- (ast_expression*)ast_binary_new(
- parser_ctx(parser),
- INSTR_SUB_F,
- (ast_expression*)arg1,
- (ast_expression*)ast_binary_new(
- parser_ctx(parser),
- INSTR_MUL_F,
- (ast_expression*)arg2,
- (ast_expression*)call
- )
- )
- )
- );
-
- vec_push(value->expression.params, arg1); /* float x (for param) */
- vec_push(value->expression.params, arg2); /* float y (for param) */
-
- vec_push(func->blocks, body); /* {{{ body }}} */
-
- INTRIN_REG(func, value);
- }
-
- return (ast_expression*)value;
-}
-
-ast_expression *intrin_exp(parser_t *parser) {
- /*
- * float exp(float x) {
- * return pow(QC_M_E, x);
- * }
- */
- static ast_value *value = NULL;
-
- if (!value) {
- ast_call *call = ast_call_new (parser_ctx(parser), intrin_func(parser, "pow"));
- ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
- ast_block *body = ast_block_new (parser_ctx(parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "exp", func, "<float>", TYPE_FLOAT);
-
- /* push arguments for params to call */
- vec_push(call->params, (ast_expression*)parser_const_float(parser, QC_M_E));
- vec_push(call->params, (ast_expression*)arg1);
-
- /* return pow(QC_M_E, x) */
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
- parser_ctx(parser),
- (ast_expression*)call
- )
- );
-
- vec_push(value->expression.params, arg1); /* float x (for param) */
-
- vec_push(func->blocks, body); /* {{{ body }}} */
-
- INTRIN_REG(func, value);
- }
-
- return (ast_expression*)value;
-}
-
-ast_expression *intrin_isnan(parser_t *parser) {
- /*
- * float isnan(float x) {
- * float local;
- * local = x;
- *
- * return (x != local);
- * }
- */
- static ast_value *value = NULL;
-
- if (!value) {
- ast_value *arg1 = ast_value_new (parser_ctx(parser), "x", TYPE_FLOAT);
- ast_value *local = ast_value_new (parser_ctx(parser), "local", TYPE_FLOAT);
- ast_block *body = ast_block_new (parser_ctx(parser));
- ast_function *func = NULL;
-
- INTRIN_VAL(value, "isnan", func, "<float>", TYPE_FLOAT);
-
- vec_push(body->locals, local);
- vec_push(body->exprs,
- (ast_expression*)ast_store_new(
- parser_ctx(parser),
- INSTR_STORE_F,
- (ast_expression*)local,
- (ast_expression*)arg1
- )
- );
-
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
- parser_ctx(parser),
- (ast_expression*)ast_binary_new(
- parser_ctx(parser),
- INSTR_NE_F,
- (ast_expression*)arg1,
- (ast_expression*)local
- )
- )
- );
-
- vec_push(value->expression.params, arg1);
-
- vec_push(func->blocks, body);
-
- INTRIN_REG(func, value);
- }
-
- return (ast_expression*)value;
-}
-
-static intrin_t intrinsics[] = {
- {&intrin_exp, "__builtin_exp", "exp"},
- {&intrin_mod, "__builtin_mod", "mod"},
- {&intrin_pow, "__builtin_pow", "pow"},
- {&intrin_isnan, "__builtin_isnan", "isnan"}