]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
Constant fold intrinsics if their arguments are constant. TODO: reference count intri...
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 202adb64dc08e22ac87011b3920b7b485d64a70d..a228f3f7edcb5d7b671db45c9142d26a0d9fb69c 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -26,6 +26,7 @@
 
 #include "gmqcc.h"
 #include "ast.h"
+#include "parser.h"
 
 #define ast_instantiate(T, ctx, destroyfn)                          \
     T* self = (T*)mem_a(sizeof(T));                                 \
@@ -368,7 +369,8 @@ ast_value* ast_value_new(lex_ctx_t ctx, const char *name, int t)
     self->getter = NULL;
     self->desc   = NULL;
 
-    self->argcounter  = NULL;
+    self->argcounter = NULL;
+    self->intrinsic = false;
 
     return self;
 }
@@ -442,6 +444,7 @@ ast_binary* ast_binary_new(lex_ctx_t ctx, int op,
     self->op = op;
     self->left = left;
     self->right = right;
+    self->right_first = false;
 
     ast_propagate_effects(self, left);
     ast_propagate_effects(self, right);
@@ -1221,7 +1224,7 @@ void ast_function_delete(ast_function *self)
     mem_d(self);
 }
 
-static const char* ast_function_label(ast_function *self, const char *prefix)
+const char* ast_function_label(ast_function *self, const char *prefix)
 {
     size_t id;
     size_t len;
@@ -1347,6 +1350,20 @@ static bool ast_global_array_set(ast_value *self)
     return true;
 }
 
+static bool check_array(ast_value *self, ast_value *array)
+{
+    if (array->expression.flags & AST_FLAG_ARRAY_INIT && !array->initlist) {
+        compile_error(ast_ctx(self), "array without size: %s", self->name);
+        return false;
+    }
+    /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
+    if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
+        compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
+        return false;
+    }
+    return true;
+}
+
 bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
 {
     ir_value *v = NULL;
@@ -1394,9 +1411,8 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                 return false;
             }
 
-            /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
-            if (!array->expression.count || array->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
-                compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)array->expression.count);
+            if (!check_array(self, array))
+                return false;
 
             elemtype = array->expression.next;
             vtype = elemtype->vtype;
@@ -1462,8 +1478,8 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         }
 
         /* same as with field arrays */
-        if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE))
-            compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
+        if (!check_array(self, self))
+            return false;
 
         v = ir_builder_create_global(ir, self->name, vtype);
         if (!v) {
@@ -1600,9 +1616,8 @@ static bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
         }
 
         /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
-        if (!self->expression.count || self->expression.count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
-            compile_error(ast_ctx(self), "Invalid array of size %lu", (unsigned long)self->expression.count);
-        }
+        if (!check_array(self, self))
+            return false;
 
         self->ir_values = (ir_value**)mem_a(sizeof(self->ir_values[0]) * self->expression.count);
         if (!self->ir_values) {
@@ -2024,6 +2039,8 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
     if ((OPTS_FLAG(SHORT_LOGIC) || OPTS_FLAG(PERL_LOGIC)) &&
         (self->op == INSTR_AND || self->op == INSTR_OR))
     {
+        /* NOTE: The short-logic path will ignore right_first */
+
         /* short circuit evaluation */
         ir_block *other, *merge;
         ir_block *from_left, *from_right;
@@ -2121,13 +2138,21 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         return true;
     }
 
-    cgen = self->left->codegen;
-    if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
-        return false;
-
-    cgen = self->right->codegen;
-    if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
-        return false;
+    if (self->right_first) {
+        cgen = self->right->codegen;
+        if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
+            return false;
+        cgen = self->left->codegen;
+        if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
+            return false;
+    } else {
+        cgen = self->left->codegen;
+        if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
+            return false;
+        cgen = self->right->codegen;
+        if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
+            return false;
+    }
 
     *out = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "bin"),
                                  self->op, left, right);
@@ -2513,6 +2538,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
     ir_block *ontrue_endblock = NULL;
     ir_block *onfalse_endblock = NULL;
     ir_block *merge = NULL;
+    int       fold  = 0;
 
     /* We don't output any value, thus also don't care about r/lvalue */
     (void)out;
@@ -2531,32 +2557,9 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
     /* update the block which will get the jump - because short-logic or ternaries may have changed this */
     cond = func->curblock;
 
-    /* eliminate branches if value is constant */
-    if (condval->vtype == TYPE_FLOAT && condval->hasvalue && condval->cvq == CV_CONST) {
-        /* don't generate if statements */
-        if (condval->constval.vfloat == 1.0f && self->on_true) {
-            if (!(ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue"))))
-                return false;
-            /* generate */
-            if (!(*(cgen = self->on_true->codegen))((ast_expression*)(self->on_true), func, false, &dummy))
-                return false;
-            if (!ir_block_create_jump(func->curblock, ast_ctx(self), ontrue))
-                return false;
-            func->curblock = ontrue;
-            return true;
-        } else if (condval->constval.vfloat == 0.0f && self->on_false) {
-            if (!(onfalse = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "onfalse"))))
-                return false;
-            /* generate */
-            if (!(*(cgen = self->on_false->codegen))((ast_expression*)(self->on_false), func, false, &dummy))
-                return false;
-            if (!ir_block_create_jump(func->curblock, ast_ctx(self), onfalse))
-                return false;
-            func->curblock = onfalse;
-            return true;
-        }
-    } 
-    /* on-true path */
+    /* try constant folding away the if */
+    if ((fold = fold_cond(condval, func, self)) != -1)
+        return fold;
 
     if (self->on_true) {
         /* create on-true block */