Move const-branch-elision into fold.c
authorDale Weiler <killfieldengine@gmail.com>
Wed, 31 Jul 2013 19:34:38 +0000 (19:34 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Wed, 31 Jul 2013 19:34:38 +0000 (19:34 +0000)
ast.c
ast.h
fold.c
parser.h

diff --git a/ast.c b/ast.c
index 202adb6..dd98a83 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));                                 \
@@ -1221,7 +1222,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;
@@ -2513,6 +2514,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,33 +2533,10 @@ 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((ast_value*)condval, func, self)) != -1)
+        return fold;
+    
     if (self->on_true) {
         /* create on-true block */
         ontrue = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "ontrue"));
diff --git a/ast.h b/ast.h
index 1f3029f..ca323a2 100644 (file)
--- a/ast.h
+++ b/ast.h
@@ -642,7 +642,7 @@ void ast_function_delete(ast_function*);
 /* For "optimized" builds this can just keep returning "foo"...
  * or whatever...
  */
-/*const char* ast_function_label(ast_function*, const char *prefix);*/
+const char* ast_function_label(ast_function*, const char *prefix);
 
 bool ast_function_codegen(ast_function *self, ir_builder *builder);
 bool ast_generate_accessors(ast_value *asvalue, ir_builder *ir);
diff --git a/fold.c b/fold.c
index 884e039..c8996cf 100644 (file)
--- a/fold.c
+++ b/fold.c
@@ -588,3 +588,35 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op
     compile_error(fold_ctx(fold), "internal error: attempted to constant for unsupported operator");
     return NULL;
 }
+
+/*
+ * These are all the actual constant folding methods that happen in the AST
+ * stage of the compiler, i.e eliminating branches for const expressions,
+ * which is the only supported thing so far.
+ */
+int fold_cond(ir_value *condval, ast_function *func, ast_ifthen *branch) {
+    if (condval->vtype == TYPE_FLOAT && condval->hasvalue && condval->cvq == CV_CONST) {
+        ast_expression_codegen *cgen;
+        ir_block               *elide;
+        ir_value               *dummy;
+        bool                    istrue  = (fold_immvalue_float(condval) == 1.0f && branch->on_true);
+        bool                    isfalse = (fold_immvalue_float(condval) == 0.0f && branch->on_false);
+        ast_expression         *path    = (istrue)  ? branch->on_true  :
+                                          (isfalse) ? branch->on_false : NULL;
+        if (!path)
+            return false;
+        if (!(elide = ir_function_create_block(ast_ctx(branch), func->ir_func, ast_function_label(func, ((istrue) ? "ontrue" : "onfalse")))))
+            return false;
+        if (!(*(cgen = path->codegen))((ast_expression*)path, func, false, &dummy))
+            return false;
+        if (!ir_block_create_jump(func->curblock, ast_ctx(branch), elide))
+            return false;
+        /*
+         * now the branch has been eliminates, and the correct block for the constant evaluation
+         * is expanded into the current block for the function.
+         */
+        func->curblock = elide;
+        return true;
+    }
+    return -1; /* nothing done */
+}
index 147d292..15c0ce4 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -112,4 +112,7 @@ ast_expression *fold_constgen_vector(fold_t *, vec3_t);
 ast_expression *fold_constgen_string(fold_t *, const char *, bool);
 bool            fold_generate       (fold_t *, ir_builder *);
 ast_expression *fold_op             (fold_t *, const oper_info *, ast_expression**);
+
+int             fold_cond           (ir_value *, ast_function *, ast_ifthen *);
+
 #endif