private static void EmitFcmpOrFcmpe(ILEmitterCtx context, bool signalNaNs) { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; bool cmpWithZero = !(op is OpCodeSimdFcond64) ? op.Bit3 : false; if (Optimizations.FastFP && Optimizations.UseSse2) { if (op.Size == 0) { Type[] typesCmp = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <float>) }; ILLabel lblNaN = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); if (cmpWithZero) { VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); } else { context.EmitLdvec(op.Rm); } context.Emit(OpCodes.Dup); context.EmitStvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp)); context.Emit(OpCodes.Brtrue_S, lblNaN); context.EmitLdc_I4(0); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), typesCmp)); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); context.EmitStflg((int)PState.CBit); context.EmitStflg((int)PState.VBit); context.Emit(OpCodes.Br_S, lblEnd); context.MarkLabel(lblNaN); context.EmitLdc_I4(1); context.Emit(OpCodes.Dup); context.EmitLdc_I4(0); context.Emit(OpCodes.Dup); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); context.EmitStflg((int)PState.CBit); context.EmitStflg((int)PState.VBit); context.MarkLabel(lblEnd); } else /* if (op.Size == 1) */ { Type[] typesCmp = new Type[] { typeof(Vector128 <double>), typeof(Vector128 <double>) }; ILLabel lblNaN = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); if (cmpWithZero) { VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); } else { context.EmitLdvec(op.Rm); } context.Emit(OpCodes.Dup); context.EmitStvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); context.Emit(OpCodes.Brtrue_S, lblNaN); context.EmitLdc_I4(0); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrderedScalar), typesCmp)); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); context.EmitStflg((int)PState.CBit); context.EmitStflg((int)PState.VBit); context.Emit(OpCodes.Br_S, lblEnd); context.MarkLabel(lblNaN); context.EmitLdc_I4(1); context.Emit(OpCodes.Dup); context.EmitLdc_I4(0); context.Emit(OpCodes.Dup); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); context.EmitStflg((int)PState.CBit); context.EmitStflg((int)PState.VBit); context.MarkLabel(lblEnd); } } else { EmitVectorExtractF(context, op.Rn, 0, op.Size); if (cmpWithZero) { if (op.Size == 0) { context.EmitLdc_R4(0f); } else /* if (op.Size == 1) */ { context.EmitLdc_R8(0d); } } else { EmitVectorExtractF(context, op.Rm, 0, op.Size); } context.EmitLdc_I4(!signalNaNs ? 0 : 1); EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare)); EmitSetNzcv(context); } }
private static void EmitSse41Fcvt_Unsigned(ILEmitterCtx context, RoundMode roundMode, bool scalar) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; // sizeF == ((OpCodeSimdShImm64)op).Size - 2 int sizeF = op.Size & 1; if (sizeF == 0) { Type[] types = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <float>) }; Type[] typesAdd = new Type[] { typeof(Vector128 <int>), typeof(Vector128 <int>) }; Type[] typesRndCvt = new Type[] { typeof(Vector128 <float>) }; Type[] typesSav = new Type[] { typeof(int) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), types)); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); if (op is OpCodeSimdShImm64 fixedOp) { int fBits = GetImmShr(fixedOp); // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) int fpScaled = 0x3F800000 + fBits * 0x800000; context.EmitLdc_I4(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), types)); } context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); context.Emit(OpCodes.Dup); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); context.EmitStvectmp(); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); context.EmitLdvectmp(); context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitStvectmp2(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), types)); context.Emit(OpCodes.Dup); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); context.EmitStvectmp(); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), types)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitStvec(op.Rd); if (scalar) { EmitVectorZero32_128(context, op.Rd); } else if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } } else /* if (sizeF == 1) */ { Type[] types = new Type[] { typeof(Vector128 <double>), typeof(Vector128 <double>) }; Type[] typesAdd = new Type[] { typeof(Vector128 <long>), typeof(Vector128 <long>) }; Type[] typesRndCvt = new Type[] { typeof(Vector128 <double>) }; Type[] typesSv = new Type[] { typeof(long), typeof(long) }; Type[] typesSav = new Type[] { typeof(long) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), types)); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); if (op is OpCodeSimdShImm64 fixedOp) { int fBits = GetImmShr(fixedOp); // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; context.EmitLdc_I8(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), types)); } context.EmitCall(typeof(Sse41).GetMethod(GetVectorSse41NameRnd(roundMode), typesRndCvt)); context.Emit(OpCodes.Dup); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); context.EmitStvectmp(); if (!scalar) { context.EmitLdvectmp(); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); } else { context.EmitLdc_I8(0L); } context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); context.EmitLdvectmp(); context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitStvectmp2(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), types)); context.Emit(OpCodes.Dup); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); context.EmitStvectmp(); if (!scalar) { context.EmitLdvectmp(); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); } else { context.EmitLdc_I8(0L); } context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitStvec(op.Rd); if (scalar) { EmitVectorZeroUpper(context, op.Rd); } } }
public static void Tbl_V(ILEmitterCtx context) { OpCodeSimdTbl64 op = (OpCodeSimdTbl64)context.CurrOp; if (Optimizations.UseSsse3) { Type[] typesCmpSflSub = new Type[] { typeof(Vector128 <sbyte>), typeof(Vector128 <sbyte>) }; Type[] typesOr = new Type[] { typeof(Vector128 <long>), typeof(Vector128 <long>) }; Type[] typesSav = new Type[] { typeof(long) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); context.EmitLdc_I8(0x0F0F0F0F0F0F0F0FL); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitStvectmp2(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); for (int index = 1; index < op.Size; index++) { context.EmitLdvec((op.Rn + index) & 0x1F); context.EmitLdvec(op.Rm); context.EmitLdc_I8(0x1010101010101010L * index); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSflSub)); context.EmitStvectmp(); context.EmitLdvectmp(); context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); } context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } } else { context.EmitLdvec(op.Rm); for (int index = 0; index < op.Size; index++) { context.EmitLdvec((op.Rn + index) & 0x1F); } switch (op.Size) { case 1: VectorHelper.EmitCall(context, nameof(VectorHelper.Tbl1_V64), nameof(VectorHelper.Tbl1_V128)); break; case 2: VectorHelper.EmitCall(context, nameof(VectorHelper.Tbl2_V64), nameof(VectorHelper.Tbl2_V128)); break; case 3: VectorHelper.EmitCall(context, nameof(VectorHelper.Tbl3_V64), nameof(VectorHelper.Tbl3_V128)); break; case 4: VectorHelper.EmitCall(context, nameof(VectorHelper.Tbl4_V64), nameof(VectorHelper.Tbl4_V128)); break; default: throw new InvalidOperationException(); } context.EmitStvec(op.Rd); } }
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 <float>), typeof(Vector128 <float>) }; 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 <float>), typeof(Vector128 <float>), typeof(byte) }; Type[] types = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <float>) }; 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 <double>), typeof(Vector128 <double>) }; 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); } }