]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
field constants - revert globals generated after fields
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 5a10154c44e1b237be43afc9cd9f36abe66bbebc..5d824d0c44e5cf62651708a6eee6c2a6bcf84fc7 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -322,6 +322,7 @@ 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->isfield  = false;
     self->cvq      = CV_NONE;
     self->hasvalue = false;
     self->uses    = 0;
@@ -997,7 +998,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);
@@ -1263,6 +1264,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;
@@ -1416,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;
@@ -1451,7 +1467,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
         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))
         {
@@ -1462,7 +1478,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
             {
                 return false;
             }
-            return ir_block_create_return(self->curblock, NULL);
+            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,10 +1966,10 @@ 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);
     }
     if (!*out) {
@@ -2025,7 +2041,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 +2065,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 +2075,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;
@@ -2149,9 +2179,9 @@ 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))
+        if (onfalse && !onfalse_endblock->final && !ir_block_create_jump(onfalse_endblock, ast_ctx(self), merge))
             return false;
 
         /* Now enter the merge block */
@@ -2160,7 +2190,7 @@ bool ast_ifthen_codegen(ast_ifthen *self, ast_function *func, bool lvalue, ir_va
 
     /* we create the if here, that way all blocks are ordered :)
      */
-    if (!ir_block_create_if(cond, condval,
+    if (!ir_block_create_if(cond, ast_ctx(self), condval,
                             (ontrue  ? ontrue  : merge),
                             (onfalse ? onfalse : merge)))
     {
@@ -2246,13 +2276,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 +2297,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);
@@ -2453,7 +2483,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 +2495,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;
     }
 
@@ -2476,7 +2506,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bpostcond)  tmpblock = bpostcond;
         else if (bprecond)   tmpblock = bprecond;
         else                 tmpblock = bbody;
-        if (!end_bbody->final && !ir_block_create_jump(end_bbody, tmpblock))
+        if (!end_bbody->final && !ir_block_create_jump(end_bbody, ast_ctx(self), tmpblock))
             return false;
     }
 
@@ -2487,7 +2517,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 +2530,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 +2568,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 +2643,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 +2652,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 +2685,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 +2701,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 +2712,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 +2745,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 +2773,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 +2841,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;