fix access to fields of vector members
authorWolfgang Bumiller <wry.git@bumiller.com>
Sat, 19 Nov 2016 15:15:26 +0000 (16:15 +0100)
committerWolfgang Bumiller <wry.git@bumiller.com>
Sat, 19 Nov 2016 15:22:18 +0000 (16:22 +0100)
When ast_member encounters the result of an ast_entfield it
has to replace the ast_entfield's codegen as we cannot
evaluate the field access first.

We then perform the same action as ast_entfield but call
vectorMember on the field before issuing the load/address
instruction.

This effectively turns the codegen of the following ast
structure:
    member_of {
        field_of {
            entity,
            a_vector
        }
        memberid
    }
into the one of this structure:
    field_of {
        entity,
        member_of {
            a_vector
            memberid
        }
    }

ast.cpp
tests/vecfields.qc [new file with mode: 0644]
tests/vecfields.tmpl [new file with mode: 0644]

diff --git a/ast.cpp b/ast.cpp
index cf8ffc7..7529acd 100644 (file)
--- a/ast.cpp
+++ b/ast.cpp
@@ -2098,13 +2098,45 @@ bool ast_member::codegen(ast_function *func, bool lvalue, ir_value **out)
         compile_error(m_context, "not an l-value (member access)");
         return false;
     }
-    if (m_outl) {
+    if (lvalue && m_outl) {
         *out = m_outl;
         return true;
     }
+    if (!lvalue && m_outr) {
+        *out = m_outr;
+        return true;
+    }
 
-    if (!m_owner->codegen(func, false, &vec))
-        return false;
+    if (ast_istype(m_owner, ast_entfield)) {
+        ir_value *ent, *field;
+        auto entfield = reinterpret_cast<ast_entfield*>(m_owner);
+        if (!entfield->m_entity->codegen(func, false, &ent))
+            return false;
+        if (!entfield->m_field->codegen(func, false, &vec))
+            return false;
+        field = vec->vectorMember(m_field);
+        if (lvalue) {
+            *out = ir_block_create_fieldaddress(func->m_curblock, m_context, func->makeLabel("mefa"),
+                                                ent, field);
+        } else {
+            *out = ir_block_create_load_from_ent(func->m_curblock, m_context, func->makeLabel("mefv"),
+                                                 ent, field, m_vtype);
+        }
+        if (!*out) {
+            compile_error(m_context, "failed to create %s instruction (output type %s)",
+                     (lvalue ? "ADDRESS" : "FIELD"),
+                     type_name[m_vtype]);
+            return false;
+        }
+        if (lvalue)
+            m_outl = *out;
+        else
+            m_outr = *out;
+        return (*out != nullptr);
+    } else {
+        if (!m_owner->codegen(func, false, &vec))
+            return false;
+    }
 
     if (vec->m_vtype != TYPE_VECTOR &&
         !(vec->m_vtype == TYPE_FIELD && m_owner->m_next->m_vtype == TYPE_VECTOR))
diff --git a/tests/vecfields.qc b/tests/vecfields.qc
new file mode 100644 (file)
index 0000000..6cc053a
--- /dev/null
@@ -0,0 +1,13 @@
+.vector v1;
+
+float set(entity e, float v) {
+       e.v1.y = v;
+       return e.v1.y;
+}
+
+void main() {
+       entity e = spawn();
+       e.v1 = '1 2 3';
+       print(ftos(set(e, 42)), " => ");
+       print(vtos(e.v1), "\n");
+}
diff --git a/tests/vecfields.tmpl b/tests/vecfields.tmpl
new file mode 100644 (file)
index 0000000..d54ba70
--- /dev/null
@@ -0,0 +1,5 @@
+I: vecfields.qc
+D: vector field member accesses
+T: -execute
+C: -std=gmqcc -fftepp
+M: 42 => '1 42 3'