diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs index 7b597be37d..f4ddc9e830 100644 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs @@ -909,6 +909,96 @@ namespace ChocolArm64.Instructions } } + public static void EmitVectorPairwiseSseOrSse2OpF(ILEmitterCtx context, string name) + { + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + int sizeF = op.Size & 1; + + if (sizeF == 0) + { + if (op.RegisterSize == RegisterSize.Simd64) + { + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.UnpackLow), types)); + + context.Emit(OpCodes.Dup); + context.EmitStvectmp(); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh), types)); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow), types)); + + context.EmitCall(typeof(Sse).GetMethod(name, types)); + + context.EmitStvec(op.Rd); + } + else /* if (op.RegisterSize == RegisterSize.Simd128) */ + { + Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }; + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + + context.EmitLdvec(op.Rn); + + context.Emit(OpCodes.Dup); + context.EmitStvectmp(); + + context.EmitLdvec(op.Rm); + + context.Emit(OpCodes.Dup); + context.EmitStvectmp2(); + + context.EmitLdc_I4(2 << 6 | 0 << 4 | 2 << 2 | 0 << 0); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + + context.EmitLdvectmp(); + context.EmitLdvectmp2(); + + context.EmitLdc_I4(3 << 6 | 1 << 4 | 3 << 2 | 1 << 0); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + + context.EmitCall(typeof(Sse).GetMethod(name, types)); + + context.EmitStvec(op.Rd); + } + } + else /* if (sizeF == 1) */ + { + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + + EmitLdvecWithCastToDouble(context, op.Rn); + + context.Emit(OpCodes.Dup); + context.EmitStvectmp(); + + EmitLdvecWithCastToDouble(context, op.Rm); + + context.Emit(OpCodes.Dup); + context.EmitStvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), types)); + + context.EmitLdvectmp(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); + + context.EmitCall(typeof(Sse2).GetMethod(name, types)); + + EmitStvecWithCastFromDouble(context, op.Rd); + } + } + [Flags] public enum SaturatingFlags {