private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; int Elems = 8 >> Op.Size; int ESize = 8 << Op.Size; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; long RoundConst = 1L << (ESize - 1); if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size + 1); Emit(); if (Round) { Context.EmitLdc_I8(RoundConst); Context.Emit(OpCodes.Add); } Context.EmitLsr(ESize); EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } }
private static void EmitVectorShrImmNarrowOpZx(AILEmitterCtx Context, bool Round) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; int Shift = GetImmShr(Op); long RoundConst = 1L << (Shift - 1); int Elems = 8 >> Op.Size; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1); if (Round) { Context.EmitLdc_I8(RoundConst); Context.Emit(OpCodes.Add); } Context.EmitLdc_I4(Shift); Context.Emit(OpCodes.Shr_Un); EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Ursra_V(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; if (AOptimizations.UseSse2 && Op.Size > 0) { Type[] TypesShs = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) }; Type[] TypesAdd = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], VectorUIntTypesPerSizeLog2[Op.Size] }; int Shift = GetImmShr(Op); int ESize = 8 << Op.Size; EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size); EmitLdvecWithUnsignedCast(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.ShiftRightLogical), TypesShs)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd)); Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd)); EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size); if (Op.RegisterSize == ARegisterSize.SIMD64) { EmitVectorZeroUpper(Context, Op.Rd); } } else { EmitVectorShrImmOpZx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate); } }
public static void EmitSaturatingNarrowOp(AILEmitterCtx Context, Action Emit, SaturatingNarrowFlags Flags) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; bool Scalar = (Flags & SaturatingNarrowFlags.Scalar) != 0; bool SignedSrc = (Flags & SaturatingNarrowFlags.SignedSrc) != 0; bool SignedDst = (Flags & SaturatingNarrowFlags.SignedDst) != 0; int Elems = !Scalar ? 8 >> Op.Size : 1; int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; if (Scalar) { EmitVectorZeroLowerTmp(Context); } if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); Emit(); EmitSatQ(Context, Op.Size, SignedSrc, SignedDst); EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void EmitVectorInsertTmpF(AILEmitterCtx Context, int Index, int Size) { Context.EmitLdvectmp(); Context.EmitLdc_I4(Index); if (Size == 0) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle)); } else if (Size == 1) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble)); } else { throw new ArgumentOutOfRangeException(nameof(Size)); } Context.EmitStvectmp(); }
public static void EmitVectorWidenRmBinaryOp(AILEmitterCtx Context, Action Emit, bool Signed) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); int Elems = 8 >> Op.Size; int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0; for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed); EmitVectorExtract(Context, Op.Rm, Part + Index, Op.Size, Signed); Emit(); EmitVectorInsertTmp(Context, Index, Op.Size + 1); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); }
private static void EmitShrImmSaturatingNarrowOp(AILEmitterCtx Context, ShrImmSaturatingNarrowFlags Flags) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; bool Scalar = (Flags & ShrImmSaturatingNarrowFlags.Scalar) != 0; bool SignedSrc = (Flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0; bool SignedDst = (Flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0; bool Round = (Flags & ShrImmSaturatingNarrowFlags.Round) != 0; int Shift = GetImmShr(Op); long RoundConst = 1L << (Shift - 1); int Elems = !Scalar ? 8 >> Op.Size : 1; int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; if (Scalar) { EmitVectorZeroLowerTmp(Context); } if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); if (Op.Size <= 1 || !Round) { if (Round) { Context.EmitLdc_I8(RoundConst); Context.Emit(OpCodes.Add); } Context.EmitLdc_I4(Shift); Context.Emit(SignedSrc ? OpCodes.Shr : OpCodes.Shr_Un); } else /* if (Op.Size == 2 && Round) */ { EmitShrImm_64(Context, SignedSrc, RoundConst, Shift); // Shift <= 32 } EmitSatQ(Context, Op.Size, SignedSrc, SignedDst); EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void EmitSaturatingNarrowOp( AILEmitterCtx Context, Action Emit, bool SignedSrc, bool SignedDst, bool Scalar) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int Elems = !Scalar ? 8 >> Op.Size : 1; int ESize = 8 << Op.Size; int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0; Context.EmitLdc_I8(0L); Context.EmitSttmp(); if (Part != 0) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); } for (int Index = 0; Index < Elems; Index++) { AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); Emit(); Context.Emit(OpCodes.Dup); Context.EmitLdc_I8(TMaxValue); Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(TMaxValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.Emit(OpCodes.Br_S, LblGeEnd); Context.MarkLabel(LblLe); Context.Emit(OpCodes.Dup); Context.EmitLdc_I8(TMinValue); Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(TMinValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.MarkLabel(LblGeEnd); if (Scalar) { EmitVectorZeroLower(Context, Op.Rd); } EmitVectorInsertTmp(Context, Part + Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if (Part == 0) { EmitVectorZeroUpper(Context, Op.Rd); } Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr)); Context.EmitLdtmp(); Context.Emit(OpCodes.Conv_I4); Context.Emit(OpCodes.Or); Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr)); }
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); } } }