]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
to support .vector's _y and _z we need to add the global-data pointing to _y and...
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index 35f00b262c6e607458dfdb86ef6c173d7c6b8cf7..7ba97eb2df65a17c8da17370697884346f8b8293 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -519,6 +519,21 @@ bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
  *IR Value
  */
 
+void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
+{
+    self->code.globaladdr = gaddr;
+    if (self->members[0]) self->members[0]->code.globaladdr = gaddr;
+    if (self->members[1]) self->members[1]->code.globaladdr = gaddr;
+    if (self->members[2]) self->members[2]->code.globaladdr = gaddr;
+}
+
+int32_t ir_value_code_addr(const ir_value *self)
+{
+    if (self->store == store_return)
+        return OFS_RETURN + self->code.addroffset;
+    return self->code.globaladdr + self->code.addroffset;
+}
+
 ir_value* ir_value_var(const char *name, int storetype, int vtype)
 {
     ir_value *self;
@@ -541,6 +556,43 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
     MEM_VECTOR_INIT(self, life);
     return self;
 }
+
+ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
+{
+    ir_value *m;
+    if (member >= 3)
+        return NULL;
+
+    if (self->members[member])
+        return self->members[member];
+
+    if (self->vtype == TYPE_VECTOR)
+    {
+        m = ir_value_var(self->name, self->store, TYPE_FLOAT);
+        if (!m)
+            return NULL;
+        m->context = self->context;
+
+        self->members[member] = m;
+        m->code.addroffset = member;
+    }
+    else if (self->vtype == TYPE_FIELD)
+    {
+        if (self->fieldtype != TYPE_VECTOR)
+            return NULL;
+        m = ir_value_var(self->name, self->store, TYPE_FIELD);
+        if (!m)
+            return NULL;
+        m->fieldtype = TYPE_FLOAT;
+        m->context = self->context;
+
+        self->members[member] = m;
+        m->code.addroffset = member;
+    }
+
+    return m;
+}
+
 MEM_VEC_FUNCTIONS(ir_value, ir_life_entry_t, life)
 MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, reads)
 MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, writes)
@@ -560,6 +612,7 @@ ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int
 
 void ir_value_delete(ir_value* self)
 {
+    size_t i;
     if (self->name)
         mem_d((void*)self->name);
     if (self->isconst)
@@ -567,6 +620,10 @@ void ir_value_delete(ir_value* self)
         if (self->vtype == TYPE_STRING)
             mem_d((void*)self->constval.vstring);
     }
+    for (i = 0; i < 3; ++i) {
+        if (self->members[i])
+            ir_value_delete(self->members[i]);
+    }
     MEM_VECTOR_CLEAR(self, reads);
     MEM_VECTOR_CLEAR(self, writes);
     MEM_VECTOR_CLEAR(self, life);
@@ -607,6 +664,15 @@ bool ir_value_set_vector(ir_value *self, vector v)
     return true;
 }
 
+bool ir_value_set_field(ir_value *self, ir_value *fld)
+{
+    if (self->vtype != TYPE_FIELD)
+        return false;
+    self->constval.vpointer = fld;
+    self->isconst = true;
+    return true;
+}
+
 bool ir_value_set_string(ir_value *self, const char *str)
 {
     if (self->vtype != TYPE_STRING)
@@ -858,22 +924,26 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b)
 
 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
 {
-    if (target->store == store_value) {
+    ir_instr *in = ir_instr_new(self, op);
+    if (!in)
+        return false;
+
+    if (target->store == store_value &&
+        (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
+    {
         fprintf(stderr, "cannot store to an SSA value\n");
         fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
+        fprintf(stderr, "instruction: %s\n", asm_instr[op].m);
+        return false;
+    }
+
+    if (!ir_instr_op(in, 0, target, true) ||
+        !ir_instr_op(in, 1, what, false)  ||
+        !ir_block_instr_add(self, in) )
+    {
         return false;
-    } else {
-        ir_instr *in = ir_instr_new(self, op);
-        if (!in)
-            return false;
-        if (!ir_instr_op(in, 0, target, true) ||
-            !ir_instr_op(in, 1, what, false)  ||
-            !ir_block_instr_add(self, in) )
-        {
-            return false;
-        }
-        return true;
     }
+    return true;
 }
 
 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
@@ -2079,11 +2149,11 @@ static bool gen_global_field(ir_value *global)
         }
 
         /* copy the field's value */
-        global->code.globaladdr = code_globals_add(code_globals_data[fld->code.globaladdr]);
+        ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr]));
     }
     else
     {
-        global->code.globaladdr = code_globals_add(0);
+        ir_value_code_setaddr(global, code_globals_add(0));
     }
     if (global->code.globaladdr < 0)
         return false;
@@ -2116,11 +2186,11 @@ static bool gen_global_pointer(ir_value *global)
             return false;
         }
 
-        global->code.globaladdr = code_globals_add(target->code.globaladdr);
+        ir_value_code_setaddr(global, code_globals_add(target->code.globaladdr));
     }
     else
     {
-        global->code.globaladdr = code_globals_add(0);
+        ir_value_code_setaddr(global, code_globals_add(0));
     }
     if (global->code.globaladdr < 0)
         return false;
@@ -2178,7 +2248,7 @@ tailcall:
              * come first: eg. optimize IFs without ELSE...
              */
 
-            stmt.o1.u1 = instr->_ops[0]->code.globaladdr;
+            stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
             stmt.o2.u1 = 0;
             stmt.o3.s1 = 0;
 
@@ -2257,7 +2327,7 @@ tailcall:
                 stmt.o3.u1 = 0;
 
                 stmt.opcode = type_store_instr[param->vtype];
-                stmt.o1.u1 = param->code.globaladdr;
+                stmt.o1.u1 = ir_value_code_addr(param);
                 stmt.o2.u1 = OFS_PARM0 + 3 * p;
                 if (code_statements_add(stmt) < 0)
                     return false;
@@ -2265,7 +2335,7 @@ tailcall:
             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.o1.u1 = ir_value_code_addr(instr->_ops[1]);
             stmt.o2.u1 = 0;
             stmt.o3.u1 = 0;
             if (code_statements_add(stmt) < 0)
@@ -2277,7 +2347,7 @@ tailcall:
                 /* 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.o2.u1 = ir_value_code_addr(retvalue);
                 stmt.o3.u1 = 0;
                 if (code_statements_add(stmt) < 0)
                     return false;
@@ -2297,21 +2367,23 @@ tailcall:
 
         /* This is the general order of operands */
         if (instr->_ops[0])
-            stmt.o3.u1 = instr->_ops[0]->code.globaladdr;
+            stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
 
         if (instr->_ops[1])
-            stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
+            stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
 
         if (instr->_ops[2])
-            stmt.o2.u1 = instr->_ops[2]->code.globaladdr;
+            stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
 
         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
         {
             stmt.o1.u1 = stmt.o3.u1;
             stmt.o3.u1 = 0;
         }
-        else if (stmt.opcode >= INSTR_STORE_F &&
-                 stmt.opcode <= INSTR_STORE_FNC)
+        else if ((stmt.opcode >= INSTR_STORE_F &&
+                  stmt.opcode <= INSTR_STORE_FNC) ||
+                 (stmt.opcode >= INSTR_STOREP_F &&
+                  stmt.opcode <= INSTR_STOREP_FNC))
         {
             /* 2-operand instructions with A -> B */
             stmt.o2.u1 = stmt.o3.u1;
@@ -2403,7 +2475,7 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     {
         /* generate code.globaladdr for ssa values */
         ir_value *v = irfun->values[i];
-        v->code.globaladdr = local_var_end + v->code.local;
+        ir_value_code_setaddr(v, local_var_end + v->code.local);
     }
     for (i = 0; i < irfun->locals_count; ++i) {
         /* fill the locals with zeros */
@@ -2452,9 +2524,9 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
 
         if (global->isconst) {
             iptr = (int32_t*)&global->constval.vfloat;
-            global->code.globaladdr = code_globals_add(*iptr);
+            ir_value_code_setaddr(global, code_globals_add(*iptr));
         } else
-            global->code.globaladdr = code_globals_add(0);
+            ir_value_code_setaddr(global, code_globals_add(0));
 
         return global->code.globaladdr >= 0;
     }
@@ -2463,9 +2535,9 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
         if (code_defs_add(def) < 0)
             return false;
         if (global->isconst)
-            global->code.globaladdr = code_globals_add(code_cachedstring(global->constval.vstring));
+            ir_value_code_setaddr(global, code_globals_add(code_cachedstring(global->constval.vstring)));
         else
-            global->code.globaladdr = code_globals_add(0);
+            ir_value_code_setaddr(global, code_globals_add(0));
         return global->code.globaladdr >= 0;
     }
     case TYPE_VECTOR:
@@ -2476,7 +2548,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
 
         if (global->isconst) {
             iptr = (int32_t*)&global->constval.vvec;
-            global->code.globaladdr = code_globals_add(iptr[0]);
+            ir_value_code_setaddr(global, code_globals_add(iptr[0]));
             if (global->code.globaladdr < 0)
                 return false;
             for (d = 1; d < type_sizeof[global->vtype]; ++d)
@@ -2485,7 +2557,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
                     return false;
             }
         } else {
-            global->code.globaladdr = code_globals_add(0);
+            ir_value_code_setaddr(global, code_globals_add(0));
             if (global->code.globaladdr < 0)
                 return false;
             for (d = 1; d < type_sizeof[global->vtype]; ++d)
@@ -2499,12 +2571,12 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
     case TYPE_FUNCTION:
         if (code_defs_add(def) < 0)
             return false;
-        global->code.globaladdr = code_globals_elements;
+        ir_value_code_setaddr(global, code_globals_elements);
         code_globals_add(code_functions_elements);
         return gen_global_function(self, global);
     case TYPE_VARIANT:
         /* assume biggest type */
-            global->code.globaladdr = code_globals_add(0);
+            ir_value_code_setaddr(global, code_globals_add(0));
             for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
                 code_globals_add(0);
             return true;
@@ -2522,13 +2594,42 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
 
     def.type   = field->vtype;
     def.offset = code_globals_elements;
-    def.name   = field->code.name = code_genstring(field->name);
+
+    /* create a global named the same as the field */
+    if (opts_standard == COMPILER_GMQCC) {
+        /* in our standard, the global gets a dot prefix */
+        size_t len = strlen(field->name);
+        char name[1024];
+
+        /* we really don't want to have to allocate this, and 1024
+         * bytes is more than enough for a variable/field name
+         */
+        if (len+2 >= sizeof(name)) {
+            printf("invalid field name size: %u\n", (unsigned int)len);
+            return false;
+        }
+
+        name[0] = '.';
+        strcpy(name+1, field->name); /* no strncpy - we used strlen above */
+        name[len+1] = 0;
+
+        def.name = code_genstring(name);
+        fld.name = def.name + 1; /* we reuse that string table entry */
+    } else {
+        /* in plain QC, there cannot be a global with the same name,
+         * and so we also name the global the same.
+         * FIXME: fteqcc should create a global as well
+         * check if it actually uses the same name. Probably does
+         */
+        def.name = code_genstring(field->name);
+        fld.name = def.name;
+    }
+
+    field->code.name = def.name;
 
     if (code_defs_add(def) < 0)
         return false;
 
-    fld.name = def.name;
-    fld.offset = code_fields_elements;
     fld.type = field->fieldtype;
 
     if (fld.type == TYPE_VOID) {
@@ -2536,13 +2637,21 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
         return false;
     }
 
+    fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
+
     if (code_fields_add(fld) < 0)
         return false;
 
-    if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype])))
+    if (!code_globals_add(fld.offset))
         return false;
+    if (fld.type == TYPE_VECTOR) {
+        if (!code_globals_add(fld.offset+1))
+            return false;
+        if (!code_globals_add(fld.offset+2))
+            return false;
+    }
 
-    field->code.globaladdr = code_globals_add(fld.offset);
+    ir_value_code_setaddr(field, code_globals_add(fld.offset));
     return field->code.globaladdr >= 0;
 }