]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
IR generation: for functions: first generate all defs, then the code, so access to...
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index 266651d03557e4a6a54ed3c054583d5e2787116a..3132685eae51c6bfa1c7550f4ca0aa6eac63c29d 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -177,7 +177,7 @@ void ir_builder_delete(ir_builder* self)
     for (i = 0; i != self->globals_count; ++i) {
         ir_value_delete(self->globals[i]);
     }
-    MEM_VECTOR_CLEAR(self, fields);
+    MEM_VECTOR_CLEAR(self, globals);
     for (i = 0; i != self->fields_count; ++i) {
         ir_value_delete(self->fields[i]);
     }
@@ -322,6 +322,8 @@ ir_function* ir_function_new(ir_builder* owner, int outtype)
     MEM_VECTOR_INIT(self, values);
     MEM_VECTOR_INIT(self, locals);
 
+    self->code_function_def = -1;
+
     self->run_id = 0;
     return self;
 }
@@ -977,7 +979,7 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b)
             if (++la == enda)
                 break;
         }
-        else if (lb->start < la->start)
+        else /* if (lb->start < la->start)  actually <= */
         {
             /* order: B A, move B forward
              * check if we hit the end with B
@@ -1077,11 +1079,11 @@ bool ir_block_create_return(ir_block *self, ir_value *v)
     if (!in)
         return false;
 
-    if (!ir_instr_op(in, 0, v, false) ||
-        !ir_block_instr_add(self, in) )
-    {
+    if (v && !ir_instr_op(in, 0, v, false))
+        return false;
+
+    if (!ir_block_instr_add(self, in))
         return false;
-    }
     return true;
 }
 
@@ -1225,7 +1227,7 @@ ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func
     in = ir_instr_new(self, INSTR_CALL0);
     if (!in)
         return NULL;
-    out = ir_value_out(self->owner, label, store_return, func->outtype);
+    out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype);
     if (!out) {
         ir_instr_delete(in);
         return NULL;
@@ -1446,11 +1448,12 @@ ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_va
 
     switch (outype)
     {
-        case TYPE_FLOAT:   op = INSTR_LOAD_F;   break;
-        case TYPE_VECTOR:  op = INSTR_LOAD_V;   break;
-        case TYPE_STRING:  op = INSTR_LOAD_S;   break;
-        case TYPE_FIELD:   op = INSTR_LOAD_FLD; break;
-        case TYPE_ENTITY:  op = INSTR_LOAD_ENT; break;
+        case TYPE_FLOAT:    op = INSTR_LOAD_F;   break;
+        case TYPE_VECTOR:   op = INSTR_LOAD_V;   break;
+        case TYPE_STRING:   op = INSTR_LOAD_S;   break;
+        case TYPE_FIELD:    op = INSTR_LOAD_FLD; break;
+        case TYPE_ENTITY:   op = INSTR_LOAD_ENT; break;
+        case TYPE_FUNCTION: op = INSTR_LOAD_FNC; break;
 #if 0
         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
@@ -1843,7 +1846,7 @@ bool ir_function_allocate_locals(ir_function *self)
 
     function_allocator alloc;
 
-    if (!self->locals_count)
+    if (!self->locals_count && !self->values_count)
         return true;
 
     MEM_VECTOR_INIT(&alloc, locals);
@@ -1906,8 +1909,9 @@ bool ir_function_allocate_locals(ir_function *self)
     self->allocated_locals = pos + alloc.sizes[alloc.sizes_count-1];
 
     /* Take over the actual slot positions */
-    for (i = 0; i < self->values_count; ++i)
+    for (i = 0; i < self->values_count; ++i) {
         self->values[i]->code.local = alloc.positions[self->values[i]->code.local];
+    }
 
     goto cleanup;
 
@@ -1945,6 +1949,15 @@ static void ir_op_read_write(int op, size_t *read, size_t *write)
         *write = 0;
         *read = 1;
         break;
+    case INSTR_STOREP_F:
+    case INSTR_STOREP_V:
+    case INSTR_STOREP_S:
+    case INSTR_STOREP_ENT:
+    case INSTR_STOREP_FLD:
+    case INSTR_STOREP_FNC:
+        *write = 0;
+        *read  = 7;
+        break;
     default:
         *write = 1;
         *read = 6;
@@ -2052,6 +2065,25 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
 #endif
         }
 
+        /* call params are read operands too */
+        for (p = 0; p < instr->params_count; ++p)
+        {
+            value = instr->params[p];
+#if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
+            if (!ir_block_living_find(self, value, NULL) &&
+                !ir_block_living_add(self, value))
+            {
+                goto on_error;
+            }
+#else
+            if (!new_reads_t_v_find(&new_reads, value, NULL))
+            {
+                if (!new_reads_t_v_add(&new_reads, value))
+                    goto on_error;
+            }
+#endif
+        }
+
         /* See which operands are read and write operands */
         ir_op_read_write(instr->opcode, &read, &write);
 
@@ -2342,13 +2374,13 @@ tailcall:
 
             if (ontrue->generated) {
                 stmt.opcode = INSTR_IF;
-                stmt.o2.s1 = (ontrue->code_start-1) - code_statements_elements;
+                stmt.o2.s1 = (ontrue->code_start) - code_statements_elements;
                 if (code_statements_add(stmt) < 0)
                     return false;
             }
             if (onfalse->generated) {
                 stmt.opcode = INSTR_IFNOT;
-                stmt.o2.s1 = (onfalse->code_start-1) - code_statements_elements;
+                stmt.o2.s1 = (onfalse->code_start) - code_statements_elements;
                 if (code_statements_add(stmt) < 0)
                     return false;
             }
@@ -2547,10 +2579,10 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     fun.firstlocal = code_globals_elements;
     fun.locals     = irfun->allocated_locals + irfun->locals_count;
 
-    local_var_end = 0;
+    local_var_end = fun.firstlocal;
     for (i = 0; i < irfun->locals_count; ++i) {
         if (!ir_builder_gen_global(ir, irfun->locals[i])) {
-            irerror(irfun->locals[i]->context, "Failed to generate global %s\n", irfun->locals[i]->name);
+            irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name);
             return false;
         }
     }
@@ -2565,7 +2597,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
         ir_value *v = irfun->values[i];
         ir_value_code_setaddr(v, local_var_end + v->code.local);
     }
-    for (i = 0; i < irfun->locals_count; ++i) {
+    for (i = 0; i < irfun->allocated_locals; ++i) {
         /* fill the locals with zeros */
         code_globals_add(0);
     }
@@ -2573,16 +2605,42 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     if (irfun->builtin)
         fun.entry = irfun->builtin;
     else {
+        irfun->code_function_def = code_functions_elements;
         fun.entry = code_statements_elements;
+        /* done in second pass: gen_global_function_code!
         if (!gen_function_code(irfun)) {
-            irerror(irfun->context, "Failed to generate code for function %s\n", irfun->name);
+            irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
             return false;
         }
+        */
     }
 
     return (code_functions_add(fun) >= 0);
 }
 
+static bool gen_global_function_code(ir_builder *ir, ir_value *global)
+{
+    prog_section_function *fundef;
+    ir_function           *irfun;
+
+    irfun = global->constval.vfunc;
+    if (irfun->builtin)
+        return true;
+
+    if (irfun->code_function_def < 0) {
+        irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
+        return false;
+    }
+    fundef = &code_functions_data[irfun->code_function_def];
+
+    fundef->entry = code_statements_elements;
+    if (!gen_function_code(irfun)) {
+        irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
+        return false;
+    }
+    return true;
+}
+
 static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
 {
     size_t           i;
@@ -2698,7 +2756,7 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
         }
 
         name[0] = '.';
-        strcpy(name+1, field->name); /* no strncpy - we used strlen above */
+        memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
         name[len+1] = 0;
 
         def.name = code_genstring(name);
@@ -2763,6 +2821,16 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
         }
     }
 
+    /* generate function code */
+    for (i = 0; i < self->globals_count; ++i)
+    {
+        if (self->globals[i]->vtype == TYPE_FUNCTION) {
+            if (!gen_global_function_code(self, self->globals[i])) {
+                return false;
+            }
+        }
+    }
+
     printf("writing '%s'...\n", filename);
     return code_write(filename);
 }
@@ -2773,6 +2841,12 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 
 #define IND_BUFSZ 1024
 
+#ifdef WIN32
+# define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
+#else
+# define strncat strncat
+#endif
+
 const char *qc_opname(int op)
 {
     if (op < 0) return "<INVALID>";