]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - intrin.c
Constant fold intrinsics if their arguments are constant. TODO: reference count intri...
[xonotic/gmqcc.git] / intrin.c
index e4f398615464c5be06d8307cd458ae12c02e4891..0075ece0ee16a6465587a6c78b8ca8b6cfb8d712 100644 (file)
--- a/intrin.c
+++ b/intrin.c
@@ -39,6 +39,7 @@
             "__builtin_" NAME,                                         \
             TYPE_FUNCTION                                              \
         );                                                             \
+        (VALUE)->intrinsic = true;                                     \
         (VALUE)->expression.next = (ast_expression*)ast_value_new (    \
             parser_ctx(intrin->parser),                                \
             STYPE,                                                     \
@@ -348,6 +349,52 @@ static ast_expression *intrin_isnan(intrin_t *intrin) {
 
     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
 
@@ -365,6 +412,7 @@ static const intrin_func_t intrinsics[] = {
     {&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", ""}
 };
 
@@ -392,6 +440,19 @@ void intrin_cleanup(intrin_t *intrin) {
     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))
+            return fold_intrin(intrin->fold, value->name, exprs);
+
+    return NULL;
+}
+
 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
     size_t       i    = 0;
     void        *find;