]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
'likely' hint for IFs
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 4da45eafbcdafdcf97d9bd13cdd94750451282b6..f5ed565e93644b202798d2ff88c33ada85d57656 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -1513,13 +1513,60 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         return true;
     }
 
+    if (OPTS_FLAG(SHORT_LOGIC) &&
+        (self->op == INSTR_AND || self->op == INSTR_OR))
+    {
+        /* short circuit evaluation */
+        ir_block *other, *merge;
+        ir_block *from_left, *from_right;
+        ir_instr *phi;
+        size_t    merge_id;
+
+        merge_id = vec_size(func->blocks);
+        merge = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_merge"));
+
+        cgen = self->left->expression.codegen;
+        if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
+            return false;
+
+        from_left = func->curblock;
+        other = ir_function_create_block(func->ir_func, ast_function_label(func, "sce_other"));
+        if (self->op == INSTR_AND) {
+            if (!ir_block_create_if(func->curblock, left, other, merge))
+                return false;
+        } else {
+            if (!ir_block_create_if(func->curblock, left, merge, other))
+                return false;
+        }
+        /* use the unlikely flag */
+        vec_last(func->curblock->instr)->likely = false;
+
+        func->curblock = other;
+        cgen = self->right->expression.codegen;
+        if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
+            return false;
+        from_right = func->curblock;
+
+        if (!ir_block_create_jump(func->curblock, merge))
+            return false;
+
+        vec_remove(func->ir_func->blocks, merge_id, 1);
+        vec_push(func->ir_func->blocks, merge);
+
+        func->curblock = merge;
+        phi = ir_block_create_phi(func->curblock, ast_function_label(func, "sce_value"), TYPE_FLOAT);
+        ir_phi_add(phi, from_left, left);
+        ir_phi_add(phi, from_right, right);
+        *out = ir_phi_value(phi);
+        self->expression.outr = *out;
+        return true;
+    }
+
     cgen = self->left->expression.codegen;
-    /* lvalue! */
     if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
         return false;
 
     cgen = self->right->expression.codegen;
-    /* rvalue! */
     if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
         return false;
 
@@ -2367,6 +2414,14 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
         }
     }
 
+    /* Jump from the last bnot to bout */
+    if (bfall && !bfall->final && !ir_block_create_jump(bfall, bout)) {
+        /*
+        astwarning(ast_ctx(bfall), WARN_???, "missing break after last case");
+        */
+        return false;
+    }
+
     /* If there was a default case, put it down here */
     if (def_case) {
         ir_block *bcase;
@@ -2389,6 +2444,8 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
     /* Jump from the last bnot to bout */
     if (!func->curblock->final && !ir_block_create_jump(func->curblock, bout))
         return false;
+    /* enter the outgoing block */
+    func->curblock = bout;
 
     /* restore the break block */
     func->breakblock = old_break;