]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
casting explicitly to boolean values in early out logic
authorWolfgang (Blub) Bumiller <blub@speed.at>
Wed, 21 Nov 2012 18:36:28 +0000 (19:36 +0100)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Wed, 21 Nov 2012 18:36:28 +0000 (19:36 +0100)
ast.c
gmqcc.h
ir.c

diff --git a/ast.c b/ast.c
index cb68f06b32cce73bb2c0d1b23f70aa52ab409e98..b04acc6fce783e9f9761505415d61cc48e058f6e 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1521,6 +1521,16 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         ir_block *from_left, *from_right;
         ir_instr *phi;
         size_t    merge_id;
+        uint16_t  notop;
+
+        /* Note about casting to true boolean values:
+         * We use a single NOT for sub expressions, and an
+         * overall NOT at the end, and for that purpose swap
+         * all the jump conditions in order for the NOT to get
+         * doubled.
+         * ie: (a && b) usually becomes (!!a ? !!b : !!a)
+         * but we translate this to (!(!a ? !a : !b))
+         */
 
         merge_id = vec_size(func->blocks);
         merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge"));
@@ -1528,10 +1538,17 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         cgen = self->left->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
             return false;
+        notop = type_not_instr[left->vtype];
+        if (notop == AINSTR_END) {
+            asterror(ast_ctx(self), "don't know how to cast to bool...");
+            return false;
+        }
+        left = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, left);
 
         from_left = func->curblock;
+
         other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other"));
-        if (self->op == INSTR_AND) {
+        if (self->op == INSTR_OR) {
             if (!ir_block_create_if(func->curblock, left, other, merge))
                 return false;
         } else {
@@ -1545,6 +1562,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         cgen = self->right->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
             return false;
+        notop = type_not_instr[right->vtype];
+        if (notop == AINSTR_END) {
+            asterror(ast_ctx(self), "don't know how to cast to bool...");
+            return false;
+        }
+        right = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_not"), notop, right);
         from_right = func->curblock;
 
         if (!ir_block_create_jump(func->curblock, merge))
@@ -1558,6 +1581,12 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         ir_phi_add(phi, from_left, left);
         ir_phi_add(phi, from_right, right);
         *out = ir_phi_value(phi);
+        notop = type_not_instr[(*out)->vtype];
+        if (notop == AINSTR_END) {
+            asterror(ast_ctx(self), "don't know how to cast to bool...");
+            return false;
+        }
+        *out = ir_block_create_unary(func->curblock, ast_function_label(func, "sce_final_not"), notop, *out);
         self->expression.outr = *out;
         return true;
     }
diff --git a/gmqcc.h b/gmqcc.h
index 265bee56d1dc28e2acb7c742cc12513429ae57a0..7861f0988e2b3648d9ade2f30ef9e2f529e2867a 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -292,6 +292,7 @@ extern uint16_t type_storep_instr[TYPE_COUNT];
 /* other useful lists */
 extern uint16_t type_eq_instr[TYPE_COUNT];
 extern uint16_t type_ne_instr[TYPE_COUNT];
+extern uint16_t type_not_instr[TYPE_COUNT];
 
 typedef struct {
     uint32_t offset;      /* Offset in file of where data begins  */
diff --git a/ir.c b/ir.c
index 232bd69d00531620b523a794638b3c2adb979ae0..91e8d7f5ca54f6bba11650eb152f4e71af9f62cc 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -171,6 +171,28 @@ uint16_t type_ne_instr[TYPE_COUNT] = {
     AINSTR_END, /* array  */
 };
 
+uint16_t type_not_instr[TYPE_COUNT] = {
+    INSTR_NOT_F, /* should use I when having integer support */
+    INSTR_NOT_S,
+    INSTR_NOT_F,
+    INSTR_NOT_V,
+    INSTR_NOT_ENT,
+    INSTR_NOT_ENT,
+    INSTR_NOT_FNC,
+    INSTR_NOT_ENT, /* should use I */
+#if 0
+    INSTR_NOT_I, /* integer type */
+#else
+    INSTR_NOT_F,
+#endif
+
+    INSTR_NOT_V, /* variant, should never be accessed */
+
+    AINSTR_END, /* struct */
+    AINSTR_END, /* union  */
+    AINSTR_END, /* array  */
+};
+
 static void irerror(lex_ctx ctx, const char *msg, ...)
 {
     va_list ap;