private static void EmitSseCall(AILEmitterCtx Context, string Name, Type Type) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; void Ldvec(int Reg) { Context.EmitLdvec(Reg); switch (Op.Size) { case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToSByte)); break; case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt16)); break; case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt32)); break; case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt64)); break; } } Ldvec(Op.Rn); Type BaseType = null; switch (Op.Size) { case 0: BaseType = typeof(Vector128 <sbyte>); break; case 1: BaseType = typeof(Vector128 <short>); break; case 2: BaseType = typeof(Vector128 <int>); break; case 3: BaseType = typeof(Vector128 <long>); break; } if (Op is AOpCodeSimdReg BinOp) { Ldvec(BinOp.Rm); Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType, BaseType })); } else { Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType })); } switch (Op.Size) { case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSByteToSingle)); break; case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16ToSingle)); break; case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32ToSingle)); break; case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt64ToSingle)); break; } Context.EmitStvec(Op.Rd); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void EmitSseOrSse2OpF(AILEmitterCtx Context, string Name, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; void Ldvec(int Reg) { Context.EmitLdvec(Reg); if (SizeF == 1) { AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToDouble)); } } Ldvec(Op.Rn); Type Type; Type BaseType; if (SizeF == 0) { Type = typeof(Sse); BaseType = typeof(Vector128 <float>); } else /* if (SizeF == 1) */ { Type = typeof(Sse2); BaseType = typeof(Vector128 <double>); } if (Op is AOpCodeSimdReg BinOp) { Ldvec(BinOp.Rm); Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType, BaseType })); } else { Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType })); } if (SizeF == 1) { AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleToSingle)); } Context.EmitStvec(Op.Rd); if (Scalar) { if (SizeF == 0) { EmitVectorZero32_128(Context, Op.Rd); } else /* if (SizeF == 1) */ { EmitVectorZeroUpper(Context, Op.Rd); } } else if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void EmitLdvecWithCastToDouble(AILEmitterCtx Context, int Reg) { Context.EmitLdvec(Reg); AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToDouble)); }
public static void EmitStvecWithCastFromDouble(AILEmitterCtx Context, int Reg) { AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleToSingle)); Context.EmitStvec(Reg); }
public static void Xtn_V(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Elems = 8 >> Op.Size; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; if (AOptimizations.UseSse41 && Op.Size < 2) { void EmitZeroVector() { switch (Op.Size) { case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16Zero)); break; case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32Zero)); break; } } //For XTN, first operand is source, second operand is 0. //For XTN2, first operand is 0, second operand is source. if (Part != 0) { EmitZeroVector(); } EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size + 1); //Set mask to discard the upper half of the wide elements. switch (Op.Size) { case 0: Context.EmitLdc_I4(0x00ff); break; case 1: Context.EmitLdc_I4(0x0000ffff); break; } Type WideType = IntTypesPerSizeLog2[Op.Size + 1]; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), new Type[] { WideType })); WideType = VectorIntTypesPerSizeLog2[Op.Size + 1]; Type[] WideTypes = new Type[] { WideType, WideType }; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), WideTypes)); if (Part == 0) { EmitZeroVector(); } //Pack values with signed saturation, the signed saturation shouldn't //saturate anything since the upper bits were masked off. Type SseType = Op.Size == 0 ? typeof(Sse2) : typeof(Sse41); Context.EmitCall(SseType.GetMethod(nameof(Sse2.PackUnsignedSaturate), WideTypes)); if (Part != 0) { //For XTN2, we additionally need to discard the upper bits //of the target register and OR the result with it. EmitVectorZeroUpper(Context, Op.Rd); EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size); Type NarrowType = VectorUIntTypesPerSizeLog2[Op.Size]; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { NarrowType, NarrowType })); } EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size); } else { if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } } }