From: Wolfgang Bumiller Date: Sat, 19 Nov 2016 15:15:26 +0000 (+0100) Subject: fix access to fields of vector members X-Git-Tag: xonotic-v0.8.5~57 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=0b94d7583cd56c5c57b35b0891d5fdf6249aaf37 fix access to fields of vector members 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 } } --- diff --git a/ast.cpp b/ast.cpp index cf8ffc7..7529acd 100644 --- 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(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 index 0000000..6cc053a --- /dev/null +++ b/tests/vecfields.qc @@ -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 index 0000000..d54ba70 --- /dev/null +++ b/tests/vecfields.tmpl @@ -0,0 +1,5 @@ +I: vecfields.qc +D: vector field member accesses +T: -execute +C: -std=gmqcc -fftepp +M: 42 => '1 42 3'