From 3c67e8f020dfbfc6fab9aa43909fc51ae10340f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 17 Jan 2013 10:23:02 +0900 Subject: [PATCH] Fix the vector/quaternion scaling instructions. It was pointed out by Blub\w (gmqcc) that OP_MUL_FV and friends were buggy when the operands overlapped (eg, x = x.x * x) as the result would become 'x.x*x.x x.y*x.x*x.x x.z*x.x*x.x' (note the x.x squared for y and z). On testing, sure enough the bug was present (and is a nice demonstration that QF's VM does NOT have strict-aliasing bugs). As a very nice benefit: the code produced by the fixes is actually faster than the broken version :). The ruamoko code used for testing: void (string fmt, ...) printf = #0; vector foo (vector x) { x = x * x.x; return x; } vector bar (vector x) { x = x.x * x; return x; } int main () { vector x = '2 3 4'; vector y = foo (x); vector z = bar (x); printf ("x=%v y=%v z=%v 2*x=%v\n", x, y, z, 2*x); return 0; } --- libs/gamecode/pr_exec.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 2e85d05a3..24778dd74 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -430,10 +430,20 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); break; case OP_MUL_FV: - VectorScale (OPB.vector_var, OPA.float_var, OPC.vector_var); + { + // avoid issues with the likes of x = x.x * x; + // makes for faster code, too + float scale = OPA.float_var; + VectorScale (OPB.vector_var, scale, OPC.vector_var); + } break; case OP_MUL_VF: - VectorScale (OPA.vector_var, OPB.float_var, OPC.vector_var); + { + // avoid issues with the likes of x = x * x.x; + // makes for faster code, too + float scale = OPB.float_var; + VectorScale (OPA.vector_var, scale, OPC.vector_var); + } break; case OP_MUL_Q: QuatMult (OPA.quat_var, OPB.quat_var, OPC.quat_var); @@ -442,10 +452,20 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); break; case OP_MUL_FQ: - QuatScale (OPB.quat_var, OPA.float_var, OPC.quat_var); + { + // avoid issues with the likes of x = x.s * x; + // makes for faster code, too + float scale = OPA.float_var; + QuatScale (OPB.quat_var, scale, OPC.quat_var); + } break; case OP_MUL_QF: - QuatScale (OPA.quat_var, OPB.float_var, OPC.quat_var); + { + // avoid issues with the likes of x = x * x.s; + // makes for faster code, too + float scale = OPB.float_var; + QuatScale (OPA.quat_var, scale, OPC.quat_var); + } break; case OP_CONJ_Q: QuatConj (OPA.quat_var, OPC.quat_var);