]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
Merging master
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index 2aa879b07b643be98996d5bc5034ef946e2787ff..1bf5513de82df32c00b76b6bd28495e3c4c48c79 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -41,7 +41,45 @@ size_t type_sizeof[TYPE_COUNT] = {
 #if 0
     1, /* TYPE_INTEGER  */
 #endif
-    3, /* TYPE_VARIANT  */
+    4, /* TYPE_QUATERNION */
+    16, /* TYPE_MATRIX */
+    16, /* TYPE_VARIANT  */
+};
+
+uint16_t type_store_instr[TYPE_COUNT] = {
+    INSTR_STORE_F, /* should use I when having integer support */
+    INSTR_STORE_S,
+    INSTR_STORE_F,
+    INSTR_STORE_V,
+    INSTR_STORE_ENT,
+    INSTR_STORE_FLD,
+    INSTR_STORE_FNC,
+    INSTR_STORE_ENT, /* should use I */
+#if 0
+    INSTR_STORE_I, /* integer type */
+#endif
+    INSTR_STORE_Q,
+    INSTR_STORE_M,
+
+    INSTR_STORE_M, /* variant, should never be accessed */
+};
+
+uint16_t type_store_instr[TYPE_COUNT] = {
+    INSTR_STOREP_F, /* should use I when having integer support */
+    INSTR_STOREP_S,
+    INSTR_STOREP_F,
+    INSTR_STOREP_V,
+    INSTR_STOREP_ENT,
+    INSTR_STOREP_FLD,
+    INSTR_STOREP_FNC,
+    INSTR_STOREP_ENT, /* should use I */
+#if 0
+    INSTR_STOREP_ENT, /* integer type */
+#endif
+    INSTR_STOREP_Q,
+    INSTR_STOREP_M,
+
+    INSTR_STOREP_M, /* variant, should never be accessed */
 };
 
 MEM_VEC_FUNCTIONS(ir_value_vector, ir_value*, v)
@@ -110,20 +148,32 @@ ir_function* ir_builder_get_function(ir_builder *self, const char *name)
     return NULL;
 }
 
-ir_function* ir_builder_create_function(ir_builder *self, const char *name)
+ir_function* ir_builder_create_function(ir_builder *self, const char *name, int outtype)
 {
     ir_function *fn = ir_builder_get_function(self, name);
     if (fn) {
         return NULL;
     }
 
-    fn = ir_function_new(self);
+    fn = ir_function_new(self, outtype);
     if (!ir_function_set_name(fn, name) ||
         !ir_builder_functions_add(self, fn) )
     {
         ir_function_delete(fn);
         return NULL;
     }
+
+    fn->value = ir_builder_create_global(self, fn->name, TYPE_FUNCTION);
+    if (!fn->value) {
+        ir_function_delete(fn);
+        return NULL;
+    }
+
+    fn->value->isconst = true;
+    fn->value->outtype = outtype;
+    fn->value->constval.vfunc = fn;
+    fn->value->context = fn->context;
+
     return fn;
 }
 
@@ -161,7 +211,7 @@ void ir_function_enumerate(ir_function*);
 bool ir_function_calculate_liferanges(ir_function*);
 bool ir_function_allocate_locals(ir_function*);
 
-ir_function* ir_function_new(ir_builder* owner)
+ir_function* ir_function_new(ir_builder* owner, int outtype)
 {
     ir_function *self;
     self = (ir_function*)mem_a(sizeof(*self));
@@ -177,7 +227,9 @@ ir_function* ir_function_new(ir_builder* owner)
     self->owner = owner;
     self->context.file = "<@no context>";
     self->context.line = 0;
-    self->retype = TYPE_VOID;
+    self->outtype = outtype;
+    self->value = NULL;
+    self->builtin = 0;
     MEM_VECTOR_INIT(self, params);
     MEM_VECTOR_INIT(self, blocks);
     MEM_VECTOR_INIT(self, values);
@@ -189,6 +241,7 @@ ir_function* ir_function_new(ir_builder* owner)
 MEM_VEC_FUNCTIONS(ir_function, ir_value*, values)
 MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks)
 MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals)
+MEM_VEC_FUNCTIONS(ir_function, int,       params)
 
 bool ir_function_set_name(ir_function *self, const char *name)
 {
@@ -217,6 +270,8 @@ void ir_function_delete(ir_function *self)
         ir_value_delete(self->locals[i]);
     MEM_VECTOR_CLEAR(self, locals);
 
+    /* self->value is deleted by the builder */
+
     mem_d(self);
 }
 
@@ -238,6 +293,9 @@ ir_block* ir_function_create_block(ir_function *self, const char *label)
 
 bool ir_function_finalize(ir_function *self)
 {
+    if (self->builtin)
+        return true;
+
     if (!ir_function_naive_phi(self))
         return false;
 
@@ -378,22 +436,22 @@ void ir_instr_delete(ir_instr *self)
     for (i = 0; i < self->phi_count; ++i) {
         size_t idx;
         if (ir_value_writes_find(self->phi[i].value, self, &idx))
-            if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
         if (ir_value_reads_find(self->phi[i].value, self, &idx))
-            if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPPRESS_EMPTY_BODY;
     }
     MEM_VECTOR_CLEAR(self, phi);
     for (i = 0; i < self->params_count; ++i) {
         size_t idx;
         if (ir_value_writes_find(self->params[i], self, &idx))
-            if (ir_value_writes_remove(self->params[i], idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_writes_remove(self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
         if (ir_value_reads_find(self->params[i], self, &idx))
-            if (ir_value_reads_remove (self->params[i], idx)) GMQCC_SUPRESS_EMPTY_BODY;
+            if (ir_value_reads_remove (self->params[i], idx)) GMQCC_SUPPRESS_EMPTY_BODY;
     }
     MEM_VECTOR_CLEAR(self, params);
-    if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
-    if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
-    if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
+    if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
+    if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
+    if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPPRESS_EMPTY_BODY;
     mem_d(self);
 }
 
@@ -499,6 +557,15 @@ bool ir_value_set_float(ir_value *self, float f)
     return true;
 }
 
+bool ir_value_set_func(ir_value *self, int f)
+{
+    if (self->vtype != TYPE_FUNCTION)
+        return false;
+    self->constval.vint = f;
+    self->isconst = true;
+    return true;
+}
+
 bool ir_value_set_vector(ir_value *self, vector v)
 {
     if (self->vtype != TYPE_VECTOR)
@@ -508,6 +575,24 @@ bool ir_value_set_vector(ir_value *self, vector v)
     return true;
 }
 
+bool ir_value_set_quaternion(ir_value *self, quaternion v)
+{
+    if (self->vtype != TYPE_QUATERNION)
+        return false;
+    self->constval.vquat = v;
+    self->isconst = true;
+    return true;
+}
+
+bool ir_value_set_matrix(ir_value *self, matrix v)
+{
+    if (self->vtype != TYPE_MATRIX)
+        return false;
+    self->constval.vmat = v;
+    self->isconst = true;
+    return true;
+}
+
 bool ir_value_set_string(ir_value *self, const char *str)
 {
     if (self->vtype != TYPE_STRING)
@@ -786,46 +871,14 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
     else
         vtype = target->vtype;
 
-    switch (vtype) {
-        case TYPE_FLOAT:
-#if 0
-            if (what->vtype == TYPE_INTEGER)
-                op = INSTR_CONV_ITOF;
-            else
-#endif
-                op = INSTR_STORE_F;
-            break;
-        case TYPE_VECTOR:
-            op = INSTR_STORE_V;
-            break;
-        case TYPE_ENTITY:
-            op = INSTR_STORE_ENT;
-            break;
-        case TYPE_STRING:
-            op = INSTR_STORE_S;
-            break;
-        case TYPE_FIELD:
-            op = INSTR_STORE_FLD;
-            break;
 #if 0
-        case TYPE_INTEGER:
-            if (what->vtype == TYPE_INTEGER)
-                op = INSTR_CONV_FTOI;
-            else
-                op = INSTR_STORE_I;
-            break;
+    if      (vtype == TYPE_FLOAT   && what->vtype == TYPE_INTEGER)
+        op = INSTR_CONV_ITOF;
+    else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
+        op = INSTR_CONV_FTOI;
 #endif
-        case TYPE_POINTER:
-#if 0
-            op = INSTR_STORE_I;
-#else
-            op = INSTR_STORE_ENT;
-#endif
-            break;
-        default:
-            /* Unknown type */
-            return false;
-    }
+        op = type_store_instr[vtype];
+
     return ir_block_create_store_op(self, op, target, what);
 }
 
@@ -842,38 +895,7 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
      */
     vtype = what->vtype;
 
-    switch (vtype) {
-        case TYPE_FLOAT:
-            op = INSTR_STOREP_F;
-            break;
-        case TYPE_VECTOR:
-            op = INSTR_STOREP_V;
-            break;
-        case TYPE_ENTITY:
-            op = INSTR_STOREP_ENT;
-            break;
-        case TYPE_STRING:
-            op = INSTR_STOREP_S;
-            break;
-        case TYPE_FIELD:
-            op = INSTR_STOREP_FLD;
-            break;
-#if 0
-        case TYPE_INTEGER:
-            op = INSTR_STOREP_I;
-            break;
-#endif
-        case TYPE_POINTER:
-#if 0
-            op = INSTR_STOREP_I;
-#else
-            op = INSTR_STOREP_ENT;
-#endif
-            break;
-        default:
-            /* Unknown type */
-            return false;
-    }
+    op = type_storep_instr[vtype];
     return ir_block_create_store_op(self, op, target, what);
 }
 
@@ -1031,14 +1053,14 @@ bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
 }
 
 /* call related code */
-ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func, int ot)
+ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
 {
     ir_value *out;
     ir_instr *in;
     in = ir_instr_new(self, INSTR_CALL0);
     if (!in)
         return NULL;
-    out = ir_value_out(self->owner, label, store_value, ot);
+    out = ir_value_out(self->owner, label, store_return, func->outtype);
     if (!out) {
         ir_instr_delete(in);
         return NULL;
@@ -1065,7 +1087,7 @@ bool ir_call_param(ir_instr* self, ir_value *v)
         return false;
     if (!ir_value_reads_add(v, self)) {
         if (!ir_instr_params_remove(self, self->params_count-1))
-            GMQCC_SUPRESS_EMPTY_BODY;
+            GMQCC_SUPPRESS_EMPTY_BODY;
         return false;
     }
     return true;
@@ -1131,7 +1153,6 @@ ir_value* ir_block_create_binop(ir_block *self,
         case INSTR_ADD_V:
         case INSTR_SUB_V:
         case INSTR_MUL_VF:
-        case INSTR_MUL_FV:
 #if 0
         case INSTR_DIV_VF:
         case INSTR_MUL_IV:
@@ -1231,6 +1252,8 @@ ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_va
         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
 #endif
+        case TYPE_QUATERNION: op = INSTR_LOAD_Q; break;
+        case TYPE_MATRIX:     op = INSTR_LOAD_M; break;
         default:
             return NULL;
     }
@@ -1334,12 +1357,22 @@ ir_value* ir_block_create_mul(ir_block *self,
             case TYPE_VECTOR:
                 op = INSTR_MUL_V;
                 break;
+            case TYPE_QUATERNION:
+                op = INSTR_MUL_Q;
+                break;
+            case TYPE_MATRIX:
+                op = INSTR_MUL_M;
+                break;
         }
     } else {
         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
             op = INSTR_MUL_VF;
         else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
             op = INSTR_MUL_FV;
+        else if ( (l == TYPE_QUATERNION && r == TYPE_FLOAT) )
+            op = INSTR_MUL_QF;
+        else if ( (l == TYPE_MATRIX && r == TYPE_FLOAT) )
+            op = INSTR_MUL_MF;
 #if 0
         else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
             op = INSTR_MUL_VI;
@@ -1619,6 +1652,9 @@ bool ir_function_allocate_locals(ir_function *self)
 
     function_allocator alloc;
 
+    if (!self->locals_count)
+        return true;
+
     MEM_VECTOR_INIT(&alloc, locals);
     MEM_VECTOR_INIT(&alloc, sizes);
     MEM_VECTOR_INIT(&alloc, positions);
@@ -1665,6 +1701,10 @@ bool ir_function_allocate_locals(ir_function *self)
     if (!function_allocator_positions_add(&alloc, 0))
         goto error;
 
+    if (alloc.sizes_count)
+        pos = alloc.positions[0] + alloc.sizes[0];
+    else
+        pos = 0;
     for (i = 1; i < alloc.sizes_count; ++i)
     {
         pos = alloc.positions[i-1] + alloc.sizes[i-1];
@@ -2165,6 +2205,8 @@ tailcall:
         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
             /* Trivial call translation:
              * copy all params to OFS_PARM*
+             * if the output's storetype is not store_return,
+             * add append a STORE instruction!
              *
              * NOTES on how to do it better without much trouble:
              * -) The liferanges!
@@ -2174,8 +2216,43 @@ tailcall:
              *      generation already. This would even include later
              *      reuse.... probably... :)
              */
-            printf("TODO: call instruction\n");
-            return false;
+            size_t p;
+            ir_value *retvalue;
+
+            for (p = 0; p < instr->params_count; ++p)
+            {
+                ir_value *param = instr->params[p];
+
+                stmt.opcode = INSTR_STORE_F;
+                stmt.o3.u1 = 0;
+
+                stmt.opcode = type_store_instr[param->vtype];
+                stmt.o1.u1 = param->code.globaladdr;
+                stmt.o2.u1 = OFS_PARM0 + 3 * p;
+                if (code_statements_add(stmt) < 0)
+                    return false;
+            }
+            stmt.opcode = INSTR_CALL0 + instr->params_count;
+            if (stmt.opcode > INSTR_CALL8)
+                stmt.opcode = INSTR_CALL8;
+            stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
+            stmt.o2.u1 = 0;
+            stmt.o3.u1 = 0;
+            if (code_statements_add(stmt) < 0)
+                return false;
+
+            retvalue = instr->_ops[0];
+            if (retvalue && retvalue->store != store_return && retvalue->life_count)
+            {
+                /* not to be kept in OFS_RETURN */
+                stmt.opcode = type_store_instr[retvalue->vtype];
+                stmt.o1.u1 = OFS_RETURN;
+                stmt.o2.u1 = retvalue->code.globaladdr;
+                stmt.o3.u1 = 0;
+                if (code_statements_add(stmt) < 0)
+                    return false;
+            }
+            continue;
         }
 
         if (instr->opcode == INSTR_STATE) {
@@ -2222,6 +2299,7 @@ tailcall:
 static bool gen_function_code(ir_function *self)
 {
     ir_block *block;
+    prog_section_statement stmt;
 
     /* Starting from entry point, we generate blocks "as they come"
      * for now. Dead blocks will not be translated obviously.
@@ -2239,6 +2317,14 @@ static bool gen_function_code(ir_function *self)
         printf("failed to generate blocks for '%s'\n", self->name);
         return false;
     }
+
+    /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
+    stmt.opcode = AINSTR_END;
+    stmt.o1.u1 = 0;
+    stmt.o2.u1 = 0;
+    stmt.o3.u1 = 0;
+    if (code_statements_add(stmt) < 0)
+        return false;
     return true;
 }
 
@@ -2250,8 +2336,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     size_t i;
     size_t local_var_end;
 
-    if (!global->isconst ||
-        !global->constval.vfunc)
+    if (!global->isconst || (!global->constval.vfunc))
     {
         printf("Invalid state of function-global: not constant: %s\n", global->name);
         return false;
@@ -2267,10 +2352,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     for (i = 0;i < 8; ++i) {
         if (i >= fun.nargs)
             fun.argsize[i] = 0;
-        else if (irfun->params[i] == TYPE_VECTOR)
-            fun.argsize[i] = 3;
         else
-            fun.argsize[i] = 1;
+            fun.argsize[i] = type_sizeof[irfun->params[i]];
     }
 
     fun.firstlocal = code_globals_elements;
@@ -2299,10 +2382,14 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
         code_globals_add(0);
     }
 
-    fun.entry      = code_statements_elements;
-    if (!gen_function_code(irfun)) {
-        printf("Failed to generate code for function %s\n", irfun->name);
-        return false;
+    if (irfun->builtin)
+        fun.entry = irfun->builtin;
+    else {
+        fun.entry = code_statements_elements;
+        if (!gen_function_code(irfun)) {
+            printf("Failed to generate code for function %s\n", irfun->name);
+            return false;
+        }
     }
 
     return (code_functions_add(fun) >= 0);
@@ -2353,25 +2440,39 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
         return global->code.globaladdr >= 0;
     }
     case TYPE_VECTOR:
+    case TYPE_QUATERNION:
+    case TYPE_MATRIX:
     {
+        size_t d;
         if (code_defs_add(def) < 0)
             return false;
 
         if (global->isconst) {
             iptr = (int32_t*)&global->constval.vvec;
             global->code.globaladdr = code_globals_add(iptr[0]);
-            if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0)
+            if (global->code.globaladdr < 0)
                 return false;
+            for (d = 1; d < type_sizeof[global->vtype]; ++d)
+            {
+                if (code_globals_add(iptr[d]) < 0)
+                    return false;
+            }
         } else {
             global->code.globaladdr = code_globals_add(0);
-            if (code_globals_add(0) < 0 || code_globals_add(0) < 0)
+            if (global->code.globaladdr < 0)
                 return false;
+            for (d = 1; d < type_sizeof[global->vtype]; ++d)
+            {
+                if (code_globals_add(0) < 0)
+                    return false;
+            }
         }
         return global->code.globaladdr >= 0;
     }
     case TYPE_FUNCTION:
         if (code_defs_add(def) < 0)
             return false;
+        global->code.globaladdr = code_globals_elements;
         code_globals_add(code_functions_elements);
         return gen_global_function(self, global);
     case TYPE_VARIANT:
@@ -2393,21 +2494,6 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 
     code_init();
 
-    /* FIXME: generate TYPE_FUNCTION globals and link them
-     * to their ir_function.
-     */
-
-    for (i = 0; i < self->functions_count; ++i)
-    {
-        ir_value    *funval;
-        ir_function *fun = self->functions[i];
-
-        funval = ir_builder_create_global(self, fun->name, TYPE_FUNCTION);
-        funval->isconst = true;
-        funval->constval.vfunc = fun;
-        funval->context = fun->context;
-    }
-
     for (i = 0; i < self->globals_count; ++i)
     {
         if (!ir_builder_gen_global(self, self->globals[i])) {
@@ -2566,6 +2652,7 @@ void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
 {
        if (v->isconst) {
                switch (v->vtype) {
+                   default:
                        case TYPE_VOID:
                                oprintf("(void)");
                                break;