public static void Sqneg_S(AILEmitterCtx Context) { EmitScalarSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); }
public static void Smull_V(AILEmitterCtx Context) { EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul)); }
public static void Sub_V(AILEmitterCtx Context) { EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); }
public static void Fmul_V(AILEmitterCtx Context) { EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul)); }
public static void Mul_Ve(AILEmitterCtx Context) { EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul)); }
public static void Fadd_V(AILEmitterCtx Context) { EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); }
public static void Fdiv_V(AILEmitterCtx Context) { EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); }
public static void B(AILEmitterCtx Context) { AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp; Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm)); }
public static void Fcmp_S(AILEmitterCtx Context) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false; //todo //Context.TryMarkCondWithoutCmp(); void EmitLoadOpers() { Context.EmitLdvecsf(Op.Rn); if (CmpWithZero) { EmitLdcImmF(Context, 0, Op.Size); } else { Context.EmitLdvecsf(Op.Rm); } } //Z = Rn == Rm EmitLoadOpers(); Context.Emit(OpCodes.Ceq); Context.Emit(OpCodes.Dup); Context.EmitStflg((int)APState.ZBit); //C = Rn >= Rm EmitLoadOpers(); Context.Emit(OpCodes.Cgt); Context.Emit(OpCodes.Or); Context.EmitStflg((int)APState.CBit); //N = Rn < Rm EmitLoadOpers(); Context.Emit(OpCodes.Clt); Context.EmitStflg((int)APState.NBit); //Handle NaN case. If any number is NaN, then NZCV = 0011. AILLabel LblNotNaN = new AILLabel(); if (CmpWithZero) { EmitNaNCheck(Context, Op.Rn); } else { EmitNaNCheck(Context, Op.Rn); EmitNaNCheck(Context, Op.Rm); Context.Emit(OpCodes.Or); } Context.Emit(OpCodes.Brfalse_S, LblNotNaN); Context.EmitLdc_I4(1); Context.EmitLdc_I4(1); Context.EmitStflg((int)APState.CBit); Context.EmitStflg((int)APState.VBit); Context.MarkLabel(LblNotNaN); }
private static void EmitVectorShl(AILEmitterCtx Context, bool Signed) { //This instruction shifts the value on vector A by the number of bits //specified on the signed, lower 8 bits of vector B. If the shift value //is greater or equal to the data size of each lane, then the result is zero. //Additionally, negative shifts produces right shifts by the negated shift value. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; int MaxShift = 8 << Op.Size; Action Emit = () => { AILLabel LblShl = new AILLabel(); AILLabel LblZero = new AILLabel(); AILLabel LblEnd = new AILLabel(); void EmitShift(OpCode ILOp) { Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(MaxShift); Context.Emit(OpCodes.Bge_S, LblZero); Context.Emit(ILOp); Context.Emit(OpCodes.Br_S, LblEnd); } Context.Emit(OpCodes.Conv_I1); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(0); Context.Emit(OpCodes.Bge_S, LblShl); Context.Emit(OpCodes.Neg); EmitShift(Signed ? OpCodes.Shr : OpCodes.Shr_Un); Context.MarkLabel(LblShl); EmitShift(OpCodes.Shl); Context.MarkLabel(LblZero); Context.Emit(OpCodes.Pop); Context.Emit(OpCodes.Pop); Context.EmitLdc_I8(0); Context.MarkLabel(LblEnd); }; if (Signed) { EmitVectorBinaryOpSx(Context, Emit); } else { EmitVectorBinaryOpZx(Context, Emit); } }
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 Ushll_V(AILEmitterCtx Context) { AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp; EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), GetImmShl(Op)); }
public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, Action Emit, SaturatingFlags Flags) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; bool Scalar = (Flags & SaturatingFlags.Scalar) != 0; bool Signed = (Flags & SaturatingFlags.Signed) != 0; bool Add = (Flags & SaturatingFlags.Add) != 0; bool Sub = (Flags & SaturatingFlags.Sub) != 0; bool Accumulate = (Flags & SaturatingFlags.Accumulate) != 0; int Bytes = Op.GetBitsCount() >> 3; int Elems = !Scalar ? Bytes >> Op.Size : 1; if (Scalar) { EmitVectorZeroLowerTmp(Context); } if (Add || Sub) { for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); if (Op.Size <= 2) { Context.Emit(Add ? OpCodes.Add : OpCodes.Sub); EmitSatQ(Context, Op.Size, true, Signed); } else /* if (Op.Size == 3) */ { if (Add) { EmitBinarySatQAdd(Context, Signed); } else /* if (Sub) */ { EmitBinarySatQSub(Context, Signed); } } EmitVectorInsertTmp(Context, Index, Op.Size); } } else if (Accumulate) { for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size, !Signed); EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed); if (Op.Size <= 2) { Context.Emit(OpCodes.Add); EmitSatQ(Context, Op.Size, true, Signed); } else /* if (Op.Size == 3) */ { EmitBinarySatQAccumulate(Context, Signed); } EmitVectorInsertTmp(Context, Index, Op.Size); } } else { for (int Index = 0; Index < Elems; Index++) { EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed); EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed); Emit(); EmitSatQ(Context, Op.Size, true, Signed); EmitVectorInsertTmp(Context, Index, Op.Size); } } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar) { EmitVectorZeroUpper(Context, Op.Rd); } }
public static void Usubw_V(AILEmitterCtx Context) { EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); }
public static void Addp_V(AILEmitterCtx Context) { EmitVectorPairwiseOpZx(Context, () => Context.Emit(OpCodes.Add)); }
public static void Not_V(AILEmitterCtx Context) { EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not)); }
public static void Fadd_S(AILEmitterCtx Context) { EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add)); }
public static void Orr_Vi(AILEmitterCtx Context) { EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or)); }
public static void Fdiv_S(AILEmitterCtx Context) { EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div)); }
public static void Mvni_V(AILEmitterCtx Context) { EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not)); }
public static void Fmul_Se(AILEmitterCtx Context) { EmitScalarBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul)); }
private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size) { bool IsSimd = GetIsSimd(Context); string Name = null; if (Size < 0 || Size > (IsSimd ? 4 : 3)) { throw new ArgumentOutOfRangeException(nameof(Size)); } if (IsSimd) { switch (Size) { case 0: Name = nameof(AMemory.ReadVector8); break; case 1: Name = nameof(AMemory.ReadVector16); break; case 2: Name = nameof(AMemory.ReadVector32); break; case 3: Name = nameof(AMemory.ReadVector64); break; case 4: Name = nameof(AMemory.ReadVector128); break; } } else { switch (Size) { case 0: Name = nameof(AMemory.ReadByte); break; case 1: Name = nameof(AMemory.ReadUInt16); break; case 2: Name = nameof(AMemory.ReadUInt32); break; case 3: Name = nameof(AMemory.ReadUInt64); break; } } Context.EmitCall(typeof(AMemory), Name); if (!IsSimd) { if (Ext == Extension.Sx32 || Ext == Extension.Sx64) { switch (Size) { case 0: Context.Emit(OpCodes.Conv_I1); break; case 1: Context.Emit(OpCodes.Conv_I2); break; case 2: Context.Emit(OpCodes.Conv_I4); break; } } if (Size < 3) { Context.Emit(Ext == Extension.Sx64 ? OpCodes.Conv_I8 : OpCodes.Conv_U8); } } }
public static void Fneg_S(AILEmitterCtx Context) { EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg)); }
public static void Rsubhn_V(AILEmitterCtx Context) { EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: true); }
public static void Neg_V(AILEmitterCtx Context) { EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); }
private static void EmitSaturatingExtNarrow(AILEmitterCtx Context, 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); int TMaxValue = (SignedDst ? (1 << (ESize - 1)) - 1 : (int)((1L << ESize) - 1L)); int TMinValue = (SignedDst ? -((1 << (ESize - 1))) : 0); Context.EmitLdc_I8(0L); Context.EmitSttmp(); for (int Index = 0; Index < Elems; Index++) { AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(TMaxValue); Context.Emit(OpCodes.Conv_U8); Context.Emit(SignedSrc ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe); Context.Emit(OpCodes.Pop); Context.EmitLdc_I4(TMaxValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.Emit(OpCodes.Br_S, LblGeEnd); Context.MarkLabel(LblLe); Context.Emit(OpCodes.Dup); Context.EmitLdc_I4(TMinValue); Context.Emit(OpCodes.Conv_I8); Context.Emit(SignedSrc ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd); Context.Emit(OpCodes.Pop); Context.EmitLdc_I4(TMinValue); Context.EmitLdc_I8(0x8000000L); Context.EmitSttmp(); Context.MarkLabel(LblGeEnd); if (Scalar) { EmitVectorZeroLower(Context, Op.Rd); } EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size); } 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 Sub_S(AILEmitterCtx Context) { EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub)); }
public static void Addhn_V(AILEmitterCtx Context) { EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: false); }
public static void Uaddl_V(AILEmitterCtx Context) { EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add)); }
public static void And_V(AILEmitterCtx Context) { EmitVectorBinaryZx(Context, () => Context.Emit(OpCodes.And)); }