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;
}
This commit is contained in:
Bill Currie 2013-01-17 10:23:02 +09:00
parent 5b47c15611
commit 3c67e8f020

View file

@ -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);