]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
Some of the output types were superfluous; others are now put into a function to...
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 7afe3fb0ccdd19b38d592e4b4b40806722b6c0a5..fc82940dcb0faf1d8063d6488454eaacdc13613a 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -322,7 +322,8 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
     self->name = name ? util_strdup(name) : NULL;
     self->expression.vtype = t;
     self->expression.next  = NULL;
-    self->constant = false;
+    self->isfield  = false;
+    self->cvq      = CV_NONE;
     self->hasvalue = false;
     self->uses    = 0;
     memset(&self->constval, 0, sizeof(self->constval));
@@ -854,9 +855,12 @@ ast_call* ast_call_new(lex_ctx ctx,
     self->params = NULL;
     self->func   = funcexpr;
 
+/*
     self->expression.vtype = funcexpr->expression.next->expression.vtype;
     if (funcexpr->expression.next->expression.next)
         self->expression.next = ast_type_copy(ctx, funcexpr->expression.next->expression.next);
+*/
+    ast_type_adopt(self, funcexpr->expression.next);
 
     return self;
 }
@@ -997,7 +1001,7 @@ ast_function* ast_function_new(lex_ctx ctx, const char *name, ast_value *vtype)
         vtype->hasvalue ||
         vtype->expression.vtype != TYPE_FUNCTION)
     {
-        compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i",
+        compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
                  (int)!vtype,
                  (int)vtype->hasvalue,
                  vtype->expression.vtype);
@@ -1074,6 +1078,17 @@ const char* ast_function_label(ast_function *self, const char *prefix)
  * But I can't imagine a pituation where the output is truly unnecessary.
  */
 
+void _ast_codegen_output_type(ast_expression_common *self, ir_value *out)
+{
+    if (out->vtype == TYPE_FIELD)
+        out->fieldtype = self->next->expression.vtype;
+    if (out->vtype == TYPE_FUNCTION)
+        out->outtype = self->next->expression.vtype;
+}
+
+#define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
+#define codegen_output_type_expr(a,o) (_ast_codegen_output_type(a,(o)))
+
 bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
 {
     (void)func;
@@ -1147,8 +1162,6 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                 compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
                 return false;
             }
-            if (vtype == TYPE_FIELD)
-                v->fieldtype = elemtype->next->expression.vtype;
             v->context = ast_ctx(self);
             array->ir_v = self->ir_v = v;
 
@@ -1166,8 +1179,6 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                     compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
                     return false;
                 }
-                if (vtype == TYPE_FIELD)
-                    array->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
                 array->ir_values[ai]->context = ast_ctx(self);
             }
             mem_d(name);
@@ -1200,8 +1211,6 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name);
             return false;
         }
-        if (vtype == TYPE_FIELD)
-            v->fieldtype = elemtype->next->expression.vtype;
         v->context = ast_ctx(self);
 
         namelen = strlen(self->name);
@@ -1218,8 +1227,6 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                 compile_error(ast_ctx(self), "ir_builder_create_global failed `%s`", name);
                 return false;
             }
-            if (vtype == TYPE_FIELD)
-                self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
             self->ir_values[ai]->context = ast_ctx(self);
         }
         mem_d(name);
@@ -1234,8 +1241,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
             return false;
         }
-        if (self->expression.vtype == TYPE_FIELD)
-            v->fieldtype = self->expression.next->expression.vtype;
+        codegen_output_type(self, v);
         v->context = ast_ctx(self);
     }
 
@@ -1263,6 +1269,18 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                 /* Cannot generate an IR value for a function,
                  * need a pointer pointing to a function rather.
                  */
+            case TYPE_FIELD:
+                if (!self->constval.vfield) {
+                    compile_error(ast_ctx(self), "field constant without vfield set");
+                    goto error;
+                }
+                if (!self->constval.vfield->ir_v) {
+                    compile_error(ast_ctx(self), "field constant generated before its field");
+                    goto error;
+                }
+                if (!ir_value_set_field(v, self->constval.vfield->ir_v))
+                    goto error;
+                break;
             default:
                 compile_error(ast_ctx(self), "TODO: global constant type %i", self->expression.vtype);
                 break;
@@ -1270,6 +1288,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
     }
 
     /* link us to the ir_value */
+    v->cvq = self->cvq;
     self->ir_v = v;
     return true;
 
@@ -1318,8 +1337,6 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
             compile_error(ast_ctx(self), "ir_function_create_local failed");
             return false;
         }
-        if (vtype == TYPE_FIELD)
-            v->fieldtype = elemtype->next->expression.vtype;
         v->context = ast_ctx(self);
 
         namelen = strlen(self->name);
@@ -1334,8 +1351,6 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
                 compile_error(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
                 return false;
             }
-            if (vtype == TYPE_FIELD)
-                self->ir_values[ai]->fieldtype = elemtype->next->expression.vtype;
             self->ir_values[ai]->context = ast_ctx(self);
         }
     }
@@ -1344,8 +1359,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
         v = ir_function_create_local(func, self->name, self->expression.vtype, param);
         if (!v)
             return false;
-        if (self->expression.vtype == TYPE_FIELD)
-            v->fieldtype = self->expression.next->expression.vtype;
+        codegen_output_type(self, v);
         v->context = ast_ctx(self);
     }
 
@@ -1374,6 +1388,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
     }
 
     /* link us to the ir_value */
+    v->cvq = self->cvq;
     self->ir_v = v;
 
     if (self->setter) {
@@ -1414,7 +1429,10 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     ec = &self->vtype->expression;
     for (i = 0; i < vec_size(ec->params); ++i)
     {
-        vec_push(irf->params, ec->params[i]->expression.vtype);
+        if (ec->params[i]->expression.vtype == TYPE_FIELD)
+            vec_push(irf->params, ec->params[i]->expression.next->expression.vtype);
+        else
+            vec_push(irf->params, ec->params[i]->expression.vtype);
         if (!self->builtin) {
             if (!ast_local_codegen(ec->params[i], self->ir_func, true))
                 return false;
@@ -1446,23 +1464,21 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     /* TODO: check return types */
     if (!self->curblock->is_return)
     {
-        /*
-        return ir_block_create_return(self->curblock, NULL);
-        */
         if (!self->vtype->expression.next ||
             self->vtype->expression.next->expression.vtype == TYPE_VOID)
         {
-            return ir_block_create_return(self->curblock, NULL);
+            return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
         }
         else if (vec_size(self->curblock->entries))
         {
             /* error("missing return"); */
             if (compile_warning(ast_ctx(self), WARN_MISSING_RETURN_VALUES,
-                                "control reaches end of non-void function (`%s`)",
-                                self->name))
+                                "control reaches end of non-void function (`%s`) via %s",
+                                self->name, self->curblock->label))
             {
                 return false;
             }
+            return ir_block_create_return(self->curblock, ast_ctx(self), NULL);
         }
     }
     return true;
@@ -1552,7 +1568,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
         ai = (ast_array_index*)self->dest;
         idx = (ast_value*)ai->index;
 
-        if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+        if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
             ai = NULL;
     }
 
@@ -1584,7 +1600,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
         if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
             return false;
 
-        call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+        call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval);
         if (!call)
             return false;
         ir_call_param(call, iridx);
@@ -1606,7 +1622,7 @@ bool ast_store_codegen(ast_store *self, ast_function *func, bool lvalue, ir_valu
         if (!(*cgen)((ast_expression*)(self->source), func, false, &right))
             return false;
 
-        if (!ir_block_create_store_op(func->curblock, self->op, left, right))
+        if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->op, left, right))
             return false;
         self->expression.outr = right;
     }
@@ -1670,7 +1686,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
                 compile_error(ast_ctx(self), "don't know how to cast to bool...");
                 return false;
             }
-            left = ir_block_create_unary(func->curblock,
+            left = ir_block_create_unary(func->curblock, ast_ctx(self),
                                          ast_function_label(func, "sce_not"),
                                          notop,
                                          left);
@@ -1679,10 +1695,10 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
 
         other = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_other"));
         if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) {
-            if (!ir_block_create_if(func->curblock, left, other, merge))
+            if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
                 return false;
         } else {
-            if (!ir_block_create_if(func->curblock, left, merge, other))
+            if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
                 return false;
         }
         /* use the likely flag */
@@ -1698,21 +1714,21 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
                 compile_error(ast_ctx(self), "don't know how to cast to bool...");
                 return false;
             }
-            right = ir_block_create_unary(func->curblock,
+            right = ir_block_create_unary(func->curblock, ast_ctx(self),
                                           ast_function_label(func, "sce_not"),
                                           notop,
                                           right);
         }
         from_right = func->curblock;
 
-        if (!ir_block_create_jump(func->curblock, merge))
+        if (!ir_block_create_jump(func->curblock, ast_ctx(self), 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);
+        phi = ir_block_create_phi(func->curblock, ast_ctx(self), 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);
@@ -1722,7 +1738,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
                 compile_error(ast_ctx(self), "don't know how to cast to bool...");
                 return false;
             }
-            *out = ir_block_create_unary(func->curblock,
+            *out = ir_block_create_unary(func->curblock, ast_ctx(self),
                                          ast_function_label(func, "sce_final_not"),
                                          notop,
                                          *out);
@@ -1741,7 +1757,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
     if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
         return false;
 
-    *out = ir_block_create_binop(func->curblock, ast_function_label(func, "bin"),
+    *out = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "bin"),
                                  self->op, left, right);
     if (!*out)
         return false;
@@ -1776,7 +1792,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
         ai = (ast_array_index*)self->dest;
         idx = (ast_value*)ai->index;
 
-        if (ast_istype(ai->index, ast_value) && idx->hasvalue)
+        if (ast_istype(ai->index, ast_value) && idx->hasvalue && idx->cvq == CV_CONST)
             ai = NULL;
     }
 
@@ -1797,7 +1813,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
         return false;
 
     /* now the binary */
-    bin = ir_block_create_binop(func->curblock, ast_function_label(func, "binst"),
+    bin = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "binst"),
                                 self->opbin, leftr, right);
     self->expression.outr = bin;
 
@@ -1822,7 +1838,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
         if (!(*cgen)((ast_expression*)(arr->setter), func, true, &funval))
             return false;
 
-        call = ir_block_create_call(func->curblock, ast_function_label(func, "store"), funval);
+        call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "store"), funval);
         if (!call)
             return false;
         ir_call_param(call, iridx);
@@ -1836,7 +1852,7 @@ bool ast_binstore_codegen(ast_binstore *self, ast_function *func, bool lvalue, i
             return false;
         self->expression.outl = leftl;
 
-        if (!ir_block_create_store_op(func->curblock, self->opstore, leftl, bin))
+        if (!ir_block_create_store_op(func->curblock, ast_ctx(self), self->opstore, leftl, bin))
             return false;
         self->expression.outr = bin;
     }
@@ -1874,7 +1890,7 @@ bool ast_unary_codegen(ast_unary *self, ast_function *func, bool lvalue, ir_valu
     if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
         return false;
 
-    *out = ir_block_create_unary(func->curblock, ast_function_label(func, "unary"),
+    *out = ir_block_create_unary(func->curblock, ast_ctx(self), ast_function_label(func, "unary"),
                                  self->op, operand);
     if (!*out)
         return false;
@@ -1910,10 +1926,10 @@ bool ast_return_codegen(ast_return *self, ast_function *func, bool lvalue, ir_va
         if (!(*cgen)((ast_expression*)(self->operand), func, false, &operand))
             return false;
 
-        if (!ir_block_create_return(func->curblock, operand))
+        if (!ir_block_create_return(func->curblock, ast_ctx(self), operand))
             return false;
     } else {
-        if (!ir_block_create_return(func->curblock, NULL))
+        if (!ir_block_create_return(func->curblock, ast_ctx(self), NULL))
             return false;
     }
 
@@ -1950,11 +1966,12 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i
 
     if (lvalue) {
         /* address! */
-        *out = ir_block_create_fieldaddress(func->curblock, ast_function_label(func, "efa"),
+        *out = ir_block_create_fieldaddress(func->curblock, ast_ctx(self), ast_function_label(func, "efa"),
                                             ent, field);
     } else {
-        *out = ir_block_create_load_from_ent(func->curblock, ast_function_label(func, "efv"),
+        *out = ir_block_create_load_from_ent(func->curblock, ast_ctx(self), ast_function_label(func, "efv"),
                                              ent, field, self->expression.vtype);
+        codegen_output_type(self, *out);
     }
     if (!*out) {
         compile_error(ast_ctx(self), "failed to create %s instruction (output type %s)",
@@ -2025,7 +2042,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva
     arr = (ast_value*)self->array;
     idx = (ast_value*)self->index;
 
-    if (!ast_istype(self->index, ast_value) || !idx->hasvalue) {
+    if (!ast_istype(self->index, ast_value) || !idx->hasvalue || idx->cvq != CV_CONST) {
         /* Time to use accessor functions */
         ast_expression_codegen *cgen;
         ir_value               *iridx, *funval;
@@ -2049,7 +2066,7 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva
         if (!(*cgen)((ast_expression*)(arr->getter), func, true, &funval))
             return false;
 
-        call = ir_block_create_call(func->curblock, ast_function_label(func, "fetch"), funval);
+        call = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "fetch"), funval);
         if (!call)
             return false;
         ir_call_param(call, iridx);
@@ -2059,10 +2076,24 @@ bool ast_array_index_codegen(ast_array_index *self, ast_function *func, bool lva
         return true;
     }
 
-    if (idx->expression.vtype == TYPE_FLOAT)
-        *out = arr->ir_values[(int)idx->constval.vfloat];
-    else if (idx->expression.vtype == TYPE_INTEGER)
-        *out = arr->ir_values[idx->constval.vint];
+    if (idx->expression.vtype == TYPE_FLOAT) {
+        unsigned int arridx = idx->constval.vfloat;
+        if (arridx >= self->array->expression.count)
+        {
+            compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+            return false;
+        }
+        *out = arr->ir_values[arridx];
+    }
+    else if (idx->expression.vtype == TYPE_INTEGER) {
+        unsigned int arridx = idx->constval.vint;
+        if (arridx >= self->array->expression.count)
+        {
+            compile_error(ast_ctx(self), "array index out of bounds: %i", arridx);
+            return false;
+        }
+        *out = arr->ir_values[arridx];
+    }
     else {
         compile_error(ast_ctx(self), "array indexing here needs an integer constant");
         return false;
@@ -2082,7 +2113,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
     ir_block *onfalse;
     ir_block *ontrue_endblock = NULL;
     ir_block *onfalse_endblock = NULL;
-    ir_block *merge;
+    ir_block *merge = NULL;
 
     /* We don't output any value, thus also don't care about r/lvalue */
     (void)out;
@@ -2149,24 +2180,24 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
         if (!merge)
             return false;
         /* add jumps ot the merge block */
-        if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, merge))
+        if (ontrue && !ontrue_endblock->final && !ir_block_create_jump(ontrue_endblock, ast_ctx(self), merge))
             return false;
-        if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, merge))
-            return false;
-
-        /* we create the if here, that way all blocks are ordered :)
-         */
-        if (!ir_block_create_if(cond, condval,
-                                (ontrue  ? ontrue  : merge),
-                                (onfalse ? onfalse : merge)))
-        {
+        if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, ast_ctx(self), merge))
             return false;
-        }
 
         /* Now enter the merge block */
         func->curblock = merge;
     }
 
+    /* we create the if here, that way all blocks are ordered :)
+     */
+    if (!ir_block_create_if(cond, ast_ctx(self), condval,
+                            (ontrue  ? ontrue  : merge),
+                            (onfalse ? onfalse : merge)))
+    {
+        return false;
+    }
+
     return true;
 }
 
@@ -2246,13 +2277,13 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_
     if (!merge)
         return false;
     /* jump to merge block */
-    if (!ir_block_create_jump(ontrue_out, merge))
+    if (!ir_block_create_jump(ontrue_out, ast_ctx(self), merge))
         return false;
-    if (!ir_block_create_jump(onfalse_out, merge))
+    if (!ir_block_create_jump(onfalse_out, ast_ctx(self), merge))
         return false;
 
     /* create if instruction */
-    if (!ir_block_create_if(cond_out, condval, ontrue, onfalse))
+    if (!ir_block_create_if(cond_out, ast_ctx(self), condval, ontrue, onfalse))
         return false;
 
     /* Now enter the merge block */
@@ -2267,7 +2298,7 @@ bool ast_ternary_codegen(ast_ternary *self, ast_function *func, bool lvalue, ir_
     }
 
     /* create PHI */
-    phi = ir_block_create_phi(merge, ast_function_label(func, "phi"), trueval->vtype);
+    phi = ir_block_create_phi(merge, ast_ctx(self), ast_function_label(func, "phi"), trueval->vtype);
     if (!phi)
         return false;
     ir_phi_add(phi, ontrue_out,  trueval);
@@ -2390,7 +2421,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
     bbreak = bout;
 
     /* The loop body... */
-    if (self->body)
+    /* if (self->body) */
     {
         bbody = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "loop_body"));
         if (!bbody)
@@ -2407,9 +2438,11 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
             func->continueblock = bbody;
 
         /* generate */
-        cgen = self->body->expression.codegen;
-        if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy))
-            return false;
+        if (self->body) {
+            cgen = self->body->expression.codegen;
+            if (!(*cgen)((ast_expression*)(self->body), func, false, &dummy))
+                return false;
+        }
 
         end_bbody = func->curblock;
         func->breakblock    = old_bbreak;
@@ -2453,7 +2486,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
     else if (bbody)      tmpblock = bbody;
     else if (bpostcond)  tmpblock = bpostcond;
     else                 tmpblock = bout;
-    if (!ir_block_create_jump(bin, tmpblock))
+    if (!ir_block_create_jump(bin, ast_ctx(self), tmpblock))
         return false;
 
     /* From precond */
@@ -2465,7 +2498,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bpostcond)  ontrue = bpostcond;
         else                 ontrue = bprecond;
         onfalse = bout;
-        if (!ir_block_create_if(end_bprecond, precond, ontrue, onfalse))
+        if (!ir_block_create_if(end_bprecond, ast_ctx(self), precond, ontrue, onfalse))
             return false;
     }
 
@@ -2475,8 +2508,8 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         if      (bincrement) tmpblock = bincrement;
         else if (bpostcond)  tmpblock = bpostcond;
         else if (bprecond)   tmpblock = bprecond;
-        else                 tmpblock = bout;
-        if (!end_bbody->final && !ir_block_create_jump(end_bbody, tmpblock))
+        else                 tmpblock = bbody;
+        if (!end_bbody->final && !ir_block_create_jump(end_bbody, ast_ctx(self), tmpblock))
             return false;
     }
 
@@ -2487,7 +2520,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bprecond)   tmpblock = bprecond;
         else if (bbody)      tmpblock = bbody;
         else                 tmpblock = bout;
-        if (!ir_block_create_jump(end_bincrement, tmpblock))
+        if (!ir_block_create_jump(end_bincrement, ast_ctx(self), tmpblock))
             return false;
     }
 
@@ -2500,7 +2533,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bincrement) ontrue = bincrement;
         else                 ontrue = bpostcond;
         onfalse = bout;
-        if (!ir_block_create_if(end_bpostcond, postcond, ontrue, onfalse))
+        if (!ir_block_create_if(end_bpostcond, ast_ctx(self), postcond, ontrue, onfalse))
             return false;
     }
 
@@ -2538,7 +2571,7 @@ bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue,
         return false;
     }
 
-    if (!ir_block_create_jump(func->curblock, target))
+    if (!ir_block_create_jump(func->curblock, ast_ctx(self), target))
         return false;
     return true;
 }
@@ -2613,7 +2646,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
             if (!(*cgen)((ast_expression*)(swcase->value), func, false, &val))
                 return false;
             /* generate the condition */
-            cond = ir_block_create_binop(func->curblock, ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
+            cond = ir_block_create_binop(func->curblock, ast_ctx(self), ast_function_label(func, "switch_eq"), cmpinstr, irop, val);
             if (!cond)
                 return false;
 
@@ -2622,12 +2655,12 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
             bnot = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "not_case"));
             if (!bcase || !bnot)
                 return false;
-            if (!ir_block_create_if(func->curblock, cond, bcase, bnot))
+            if (!ir_block_create_if(func->curblock, ast_ctx(self), cond, bcase, bnot))
                 return false;
 
             /* Make the previous case-end fall through */
             if (bfall && !bfall->final) {
-                if (!ir_block_create_jump(bfall, bcase))
+                if (!ir_block_create_jump(bfall, ast_ctx(self), bcase))
                     return false;
             }
 
@@ -2655,7 +2688,7 @@ 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)) {
+    if (bfall && !bfall->final && !ir_block_create_jump(bfall, ast_ctx(self), bout)) {
         /*
         astwarning(ast_ctx(bfall), WARN_???, "missing break after last case");
         */
@@ -2671,7 +2704,7 @@ bool ast_switch_codegen(ast_switch *self, ast_function *func, bool lvalue, ir_va
 
         /* Insert the fallthrough jump */
         if (def_bfall && !def_bfall->final) {
-            if (!ir_block_create_jump(def_bfall, bcase))
+            if (!ir_block_create_jump(def_bfall, ast_ctx(self), bcase))
                 return false;
         }
 
@@ -2682,7 +2715,7 @@ 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))
+    if (!func->curblock->final && !ir_block_create_jump(func->curblock, ast_ctx(self), bout))
         return false;
     /* enter the outgoing block */
     func->curblock = bout;
@@ -2715,7 +2748,7 @@ bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_valu
         return false;
     }
     if (!func->curblock->final) {
-        if (!ir_block_create_jump(func->curblock, self->irblock))
+        if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->irblock))
             return false;
     }
 
@@ -2743,14 +2776,14 @@ bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value
         if (self->irblock_from) {
             /* we already tried once, this is the callback */
             self->irblock_from->final = false;
-            if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) {
+            if (!ir_block_create_jump(self->irblock_from, ast_ctx(self), self->target->irblock)) {
                 compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
                 return false;
             }
         }
         else
         {
-            if (!ir_block_create_jump(func->curblock, self->target->irblock)) {
+            if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->target->irblock)) {
                 compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
                 return false;
             }
@@ -2811,7 +2844,7 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value
         vec_push(params, param);
     }
 
-    callinstr = ir_block_create_call(func->curblock, ast_function_label(func, "call"), funval);
+    callinstr = ir_block_create_call(func->curblock, ast_ctx(self), ast_function_label(func, "call"), funval);
     if (!callinstr)
         goto error;
 
@@ -2822,6 +2855,8 @@ bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value
     *out = ir_call_value(callinstr);
     self->expression.outr = *out;
 
+    codegen_output_type(self, *out);
+
     vec_free(params);
     return true;
 error: