internal void EmitBinary(BinOpKind op)
{
//FIXME it might be an issue if arguments are not of type Vector4f
MethodInfo mi = null;
switch (op) {
case BinOpKind.Add:
mi = typeof (Vector4f).GetMethod ("op_Addition");
break;
case BinOpKind.Sub:
mi = typeof (Vector4f).GetMethod ("op_Subtraction");
break;
case BinOpKind.Mul:
mi = typeof (Vector4f).GetMethod ("op_Multiply");
break;
case BinOpKind.Max:
mi = typeof (VectorOperations).GetMethod ("Max", new Type[] { typeof (Vector4f), typeof (Vector4f)});
break;
case BinOpKind.Dp3:
//This is a very fuck'd up code sequence, figure out how to speed it up
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Multiply"));
ilgen.Emit (OpCodes.Dup);
ilgen.Emit (OpCodes.Dup);
//FIXME we could use HorizontalAdd for this step
EmitShuffle (ShuffleSel.XFromY); //[x,y,z,w] [x,y,z,w] [y,y,z,w]
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Addition")); //[x,y,z,w] [x + y,_,_,_]
EmitShuffle (ShuffleSel.ZFromY); //[x,y,z,w] [_,_,x + y, _]
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Addition")); //[_,_, x + y + z, _]
EmitShuffle (ShuffleSel.ExpandZ); //[dp3, dp3, dp3, dp3]
break;
case BinOpKind.Dp4:
//We should use things like HorizontalAdd or the new Dp instruction
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Multiply"));
ilgen.Emit (OpCodes.Dup);
EmitShuffle (ShuffleSel.XFromY | ShuffleSel.ZFromW); //[x,y,z,w] [y,y,w,w]
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Addition")); //[x + y,_,z + w,_]
ilgen.Emit (OpCodes.Dup); //[x + y,_,z + w,_] [x + y,_,z + w,_]
EmitShuffle (ShuffleSel.XFromZ); //[x + y,_,_,_] [z + w,_,_,_]
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_Addition")); //[x + y + z + w,_,_,_]
EmitShuffle (ShuffleSel.ExpandX); //[dp4, dp4, dp4, dp4]
break;
case BinOpKind.Min:
mi = typeof (VectorOperations).GetMethod ("Min", new Type[] { typeof (Vector4f), typeof (Vector4f)});
break;
case BinOpKind.Slt:
case BinOpKind.Sge:
//XXX hoist the constant out of the loop
mi = typeof (VectorOperations).GetMethod ("CompareLessThan", new Type[] { typeof (Vector4f), typeof (Vector4f)});
ilgen.Emit (OpCodes.Ldc_R4, 1f);
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetConstructor (new Type [] {typeof (float) }));
if (op == BinOpKind.Slt)
ilgen.Emit (OpCodes.Call, typeof (Vector4f).GetMethod ("op_BitwiseAnd"));
else
ilgen.Emit (OpCodes.Call, typeof (VectorOperations).GetMethod ("AndNot", new Type[] { typeof (Vector4f), typeof (Vector4f)}));
break;
default:
throw new Exception ("can't handle binop " + op);
}
if (mi != null)
ilgen.Emit (OpCodes.Call, mi);
}