public static void EmitSseOrSse2CallF(AILEmitterCtx Context, string Name) { 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 (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Bsl_V(AILEmitterCtx Context) { if (AOptimizations.UseSse2) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; Type[] Types = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], VectorUIntTypesPerSizeLog2[Op.Size] }; EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size); EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types)); EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), Types)); EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types)); EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } else { EmitVectorTernaryOpZx(Context, () => { Context.EmitSttmp(); Context.EmitLdtmp(); Context.Emit(OpCodes.Xor); Context.Emit(OpCodes.And); Context.EmitLdtmp(); Context.Emit(OpCodes.Xor); }); } }
public static void Fcvtl_V(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; int Elems = 4 >> SizeF; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; for (int Index = 0; Index < Elems; Index++) { if (SizeF == 0) { EmitVectorExtractZx(Context, Op.Rn, Part + Index, 1); Context.Emit(OpCodes.Conv_U2); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCall(typeof(ASoftFloat16_32), nameof(ASoftFloat16_32.FPConvert)); } else /* if (SizeF == 1) */ { EmitVectorExtractF(Context, Op.Rn, Part + Index, 0); Context.Emit(OpCodes.Conv_R8); } EmitVectorInsertTmpF(Context, Index, SizeF); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); }
public static void EmitWriteCall(AILEmitterCtx Context, int Size) { if (Size < 0 || Size > 4) { throw new ArgumentOutOfRangeException(nameof(Size)); } if (Size < 3) { Context.Emit(OpCodes.Conv_I4); } string Name = null; switch (Size) { case 0: Name = nameof(AMemory.WriteByte); break; case 1: Name = nameof(AMemory.WriteUInt16); break; case 2: Name = nameof(AMemory.WriteUInt32); break; case 3: Name = nameof(AMemory.WriteUInt64); break; case 4: Name = nameof(AMemory.WriteVector128); break; } Context.EmitCall(typeof(AMemory), Name); }
public static void Frinta_S(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; Context.EmitLdvecsf(Op.Rn); Context.EmitLdc_I4((int)MidpointRounding.AwayFromZero); MethodInfo MthdInfo; if (Op.Size == 0) { Type[] Types = new Type[] { typeof(float), typeof(MidpointRounding) }; MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); } else if (Op.Size == 1) { Type[] Types = new Type[] { typeof(double), typeof(MidpointRounding) }; MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); } else { throw new InvalidOperationException(); } Context.EmitCall(MthdInfo); Context.EmitStvecsf(Op.Rd); }
public static void Und(AILEmitterCtx Context) { AOpCode Op = Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdc_I8(Op.Position); Context.EmitLdc_I4(Op.RawOpCode); string MthdName = nameof(AThreadState.OnUndefined); MethodInfo MthdInfo = typeof(AThreadState).GetMethod(MthdName, Binding); Context.EmitCall(MthdInfo); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } else { Context.EmitLdc_I8(Op.Position + 4); Context.Emit(OpCodes.Ret); } }
public static void Frintm_S(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; Context.EmitLdvecsf(Op.Rn); MethodInfo MthdInfo; if (Op.Size == 0) { MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }); } else if (Op.Size == 1) { MthdInfo = typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }); } else { throw new InvalidOperationException(); } Context.EmitCall(MthdInfo); Context.EmitStvecsf(Op.Rd); }
public static void Fcvtl_V(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; int Elems = 4 >> SizeF; int Part = Context.CurrOp.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; for (int Index = 0; Index < Elems; Index++) { if (SizeF == 0) { EmitVectorExtractZx(Context, Op.Rn, Part + Index, 1); Context.Emit(OpCodes.Conv_U2); Context.EmitCall(typeof(ASoftFloat), nameof(ASoftFloat.ConvertHalfToSingle)); } else /* if (SizeF == 1) */ { EmitVectorExtractF(Context, Op.Rn, Part + Index, 0); Context.Emit(OpCodes.Conv_R8); } EmitVectorInsertF(Context, Op.Rd, Index, SizeF); } }
public static void Ushr_V(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; if (AOptimizations.UseSse2 && Op.Size > 0) { Type[] TypesSrl = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) }; EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size); Context.EmitLdc_I4(GetImmShr(Op)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), TypesSrl)); EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } else { EmitShrImmOp(Context, ShrImmFlags.VectorZx); } }
public static void Sbc(AILEmitterCtx Context) { EmitDataLoadOpers(Context); Context.Emit(OpCodes.Sub); Context.EmitLdflg((int)APState.CBit); Type[] MthdTypes = new Type[] { typeof(bool) }; MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); Context.EmitCall(MthdInfo); Context.EmitLdc_I4(1); Context.Emit(OpCodes.Xor); if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) { Context.Emit(OpCodes.Conv_I8); } Context.Emit(OpCodes.Sub); EmitDataStore(Context); }
private static void EmitSbc(AILEmitterCtx Context, bool SetFlags) { EmitDataLoadOpers(Context); Context.Emit(OpCodes.Sub); Context.EmitLdflg((int)APState.CBit); Type[] MthdTypes = new Type[] { typeof(bool) }; MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes); Context.EmitCall(MthdInfo); Context.EmitLdc_I4(1); Context.Emit(OpCodes.Xor); if (Context.CurrOp.RegisterSize != ARegisterSize.Int32) { Context.Emit(OpCodes.Conv_U8); } Context.Emit(OpCodes.Sub); if (SetFlags) { Context.EmitZNFlagCheck(); EmitSbcsCCheck(Context); EmitSubsVCheck(Context); } EmitDataStore(Context); }
public static void EmitRoundMathCall(AILEmitterCtx Context, MidpointRounding RoundMode) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; int SizeF = Op.Size & 1; Context.EmitLdc_I4((int)RoundMode); MethodInfo MthdInfo; Type[] Types = new Type[] { null, typeof(MidpointRounding) }; Types[0] = SizeF == 0 ? typeof(float) : typeof(double); if (SizeF == 0) { MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types); } else /* if (SizeF == 1) */ { MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); } Context.EmitCall(MthdInfo); }
private static void EmitBarrier(AILEmitterCtx Context) { //Note: This barrier is most likely not necessary, and probably //doesn't make any difference since we need to do a ton of stuff //(software MMU emulation) to read or write anything anyway. Context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier)); }
public static void EmitRoundMathCall(AILEmitterCtx Context, MidpointRounding RoundMode) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; Context.EmitLdc_I4((int)RoundMode); MethodInfo MthdInfo; Type[] Types = new Type[] { null, typeof(MidpointRounding) }; Types[0] = Op.Size == 0 ? typeof(float) : typeof(double); if (Op.Size == 0) { MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); } else if (Op.Size == 1) { MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types); } else { throw new InvalidOperationException(); } Context.EmitCall(MthdInfo); }
private static void EmitMathOp3(AILEmitterCtx Context, string Name) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; Context.EmitLdvecsf(Op.Rn); Context.EmitLdvecsf(Op.Rm); MethodInfo MthdInfo; if (Op.Size == 0) { MthdInfo = typeof(MathF).GetMethod(Name, new Type[] { typeof(float), typeof(float) }); } else if (Op.Size == 1) { MthdInfo = typeof(Math).GetMethod(Name, new Type[] { typeof(double), typeof(double) }); } else { throw new InvalidOperationException(); } Context.EmitCall(MthdInfo); Context.EmitStvecsf(Op.Rd); }
public static void Fcvt_S(AILEmitterCtx Context) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; if (AOptimizations.UseSse2) { if (Op.Size == 1 && Op.Opc == 0) { //Double -> Single. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleZero)); EmitLdvecWithCastToDouble(Context, Op.Rn); Type[] Types = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <double>) }; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), Types)); Context.EmitStvec(Op.Rd); } else if (Op.Size == 0 && Op.Opc == 1) { //Single -> Double. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleZero)); Context.EmitLdvec(Op.Rn); Type[] Types = new Type[] { typeof(Vector128 <double>), typeof(Vector128 <float>) }; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), Types)); EmitStvecWithCastFromDouble(Context, Op.Rd); } else { //Invalid encoding. throw new InvalidOperationException(); } } else { EmitVectorExtractF(Context, Op.Rn, 0, Op.Size); EmitFloatCast(Context, Op.Opc); EmitScalarSetF(Context, Op.Rd, Op.Opc); } }
public static void Fmadd_S(AILEmitterCtx Context) { if (AOptimizations.UseSse2) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; if (Op.Size == 0) { Context.EmitLdvec(Op.Ra); Context.EmitLdvec(Op.Rn); Context.EmitLdvec(Op.Rm); Type[] Types = new Type[] { typeof(Vector128 <float>), typeof(Vector128 <float>) }; Context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), Types)); Context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AddScalar), Types)); Context.EmitStvec(Op.Rd); EmitVectorZero32_128(Context, Op.Rd); } else /* if (Op.Size == 1) */ { EmitLdvecWithCastToDouble(Context, Op.Ra); EmitLdvecWithCastToDouble(Context, Op.Rn); EmitLdvecWithCastToDouble(Context, Op.Rm); Type[] Types = new Type[] { typeof(Vector128 <double>), typeof(Vector128 <double>) }; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), Types)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AddScalar), Types)); EmitStvecWithCastFromDouble(Context, Op.Rd); EmitVectorZeroUpper(Context, Op.Rd); } } else { EmitScalarTernaryRaOpF(Context, () => { Context.Emit(OpCodes.Mul); Context.Emit(OpCodes.Add); }); } }
private static void EmitVectorSmax(AILEmitterCtx Context) { Type[] Types = new Type[] { typeof(long), typeof(long) }; MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types); EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo)); }
public static void Smin_V(AILEmitterCtx Context) { Type[] Types = new Type[] { typeof(long), typeof(long) }; MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo)); }
public static void Uminp_V(AILEmitterCtx Context) { Type[] Types = new Type[] { typeof(ulong), typeof(ulong) }; MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types); EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo)); }
private static void EmitAbd(AILEmitterCtx Context) { Context.Emit(OpCodes.Sub); Type[] Types = new Type[] { typeof(long) }; Context.EmitCall(typeof(Math).GetMethod(nameof(Math.Abs), Types)); }
public static void Srsra_V(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; if (AOptimizations.UseSse2 && Op.Size > 0 && Op.Size < 3) { Type[] TypesShs = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], typeof(byte) }; Type[] TypesAdd = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], VectorIntTypesPerSizeLog2[Op.Size] }; int Shift = GetImmShr(Op); int ESize = 8 << Op.Size; EmitLdvecWithSignedCast(Context, Op.Rd, Op.Size); EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size); Context.Emit(OpCodes.Dup); Context.EmitStvectmp(); Context.EmitLdc_I4(ESize - Shift); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), TypesShs)); Context.EmitLdc_I4(ESize - 1); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), TypesShs)); Context.EmitLdvectmp(); Context.EmitLdc_I4(Shift); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), TypesShs)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd)); EmitStvecWithSignedCast(Context, Op.Rd, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } else { EmitVectorShrImmOpSx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate); } }
private static void EmitNaNCheck(AILEmitterCtx Context, int Index) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; Context.EmitLdvecsf(Index); if (Op.Size == 0) { Context.EmitCall(typeof(float), nameof(float.IsNaN)); } else if (Op.Size == 1) { Context.EmitCall(typeof(double), nameof(double.IsNaN)); } else { throw new InvalidOperationException(); } }
private static void EmitNaNCheck(AILEmitterCtx Context, int Reg) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; EmitVectorExtractF(Context, Reg, 0, Op.Size); if (Op.Size == 0) { Context.EmitCall(typeof(float), nameof(float.IsNaN)); } else if (Op.Size == 1) { Context.EmitCall(typeof(double), nameof(double.IsNaN)); } else { throw new InvalidOperationException(); } }
private static void EmitSse42Crc32(AILEmitterCtx Context, Type TCrc, Type TData) { AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp; Context.EmitLdintzr(Op.Rn); Context.EmitLdintzr(Op.Rm); Context.EmitCall(typeof(Sse42).GetMethod(nameof(Sse42.Crc32), new Type[] { TCrc, TData })); Context.EmitStintzr(Op.Rd); }
public static void EmitSoftFloatCall(AILEmitterCtx Context, string Name) { IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp; Type Type = (Op.Size & 1) == 0 ? typeof(ASoftFloat_32) : typeof(ASoftFloat_64); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCall(Type, Name); }
private static void EmitMemoryCall(AILEmitterCtx Context, string Name, int Rn = -1) { Context.EmitLdarg(ATranslatedSub.MemoryArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); if (Rn != -1) { Context.EmitLdint(Rn); } Context.EmitCall(typeof(AMemory), Name); }
public static void EmitWriteCall(AILEmitterCtx Context, int Size) { bool IsSimd = GetIsSimd(Context); string Name = null; if (Size < 0 || Size > (IsSimd ? 4 : 3)) { throw new ArgumentOutOfRangeException(nameof(Size)); } if (Size < 3 && !IsSimd) { Context.Emit(OpCodes.Conv_I4); } if (IsSimd) { switch (Size) { case 0: Name = nameof(AMemory.WriteVector8); break; case 1: Name = nameof(AMemory.WriteVector16); break; case 2: Name = nameof(AMemory.WriteVector32); break; case 3: Name = nameof(AMemory.WriteVector64); break; case 4: Name = nameof(AMemory.WriteVector128); break; } } else { switch (Size) { case 0: Name = nameof(AMemory.WriteByte); break; case 1: Name = nameof(AMemory.WriteUInt16); break; case 2: Name = nameof(AMemory.WriteUInt32); break; case 3: Name = nameof(AMemory.WriteUInt64); break; } } Context.EmitCall(typeof(AMemory), Name); }
public static void Dup_Gp(AILEmitterCtx Context) { AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp; if (AOptimizations.UseSse2) { Context.EmitLdintzr(Op.Rn); switch (Op.Size) { case 0: Context.Emit(OpCodes.Conv_U1); break; case 1: Context.Emit(OpCodes.Conv_U2); break; case 2: Context.Emit(OpCodes.Conv_U4); break; } Type[] Types = new Type[] { UIntTypesPerSizeLog2[Op.Size] }; Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), Types)); EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } else { int Bytes = Op.GetBitsCount() >> 3; int Elems = Bytes >> Op.Size; for (int Index = 0; Index < Elems; Index++) { Context.EmitLdintzr(Op.Rn); EmitVectorInsert(Context, Op.Rd, Index, Op.Size); } if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } }
public static void Svc(AILEmitterCtx Context) { AOpCodeException Op = (AOpCodeException)Context.CurrOp; Context.EmitStoreState(); Context.EmitLdarg(ATranslatedSub.RegistersArgIdx); Context.EmitLdc_I4(Op.Id); Context.EmitCall(typeof(ARegisters), nameof(ARegisters.OnSvcCall)); if (Context.CurrBlock.Next != null) { Context.EmitLoadState(Context.CurrBlock.Next); } }