diff --git a/AOpCodeTable.cs b/AOpCodeTable.cs index 5ea38b0..74d4915 100644 --- a/AOpCodeTable.cs +++ b/AOpCodeTable.cs @@ -380,8 +380,16 @@ namespace ChocolArm64 SetA64("0>001110<<100000011110xxxxxxxxxx", AInstEmit.Sqabs_V, typeof(AOpCodeSimd)); SetA64("01011110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_S, typeof(AOpCodeSimdReg)); SetA64("0>001110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_V, typeof(AOpCodeSimdReg)); + SetA64("01011110011xxxxx101101xxxxxxxxxx", AInstEmit.Sqdmulh_S, typeof(AOpCodeSimdReg)); + SetA64("01011110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqdmulh_S, typeof(AOpCodeSimdReg)); + SetA64("0x001110011xxxxx101101xxxxxxxxxx", AInstEmit.Sqdmulh_V, typeof(AOpCodeSimdReg)); + SetA64("0x001110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqdmulh_V, typeof(AOpCodeSimdReg)); SetA64("01111110xx100000011110xxxxxxxxxx", AInstEmit.Sqneg_S, typeof(AOpCodeSimd)); SetA64("0>101110<<100000011110xxxxxxxxxx", AInstEmit.Sqneg_V, typeof(AOpCodeSimd)); + SetA64("01111110011xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_S, typeof(AOpCodeSimdReg)); + SetA64("01111110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_S, typeof(AOpCodeSimdReg)); + SetA64("0x101110011xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_V, typeof(AOpCodeSimdReg)); + SetA64("0x101110101xxxxx101101xxxxxxxxxx", AInstEmit.Sqrdmulh_V, typeof(AOpCodeSimdReg)); SetA64("0x00111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_V, typeof(AOpCodeSimdShImm)); SetA64("01011110xx1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_S, typeof(AOpCodeSimdReg)); SetA64("0>001110<<1xxxxx001011xxxxxxxxxx", AInstEmit.Sqsub_V, typeof(AOpCodeSimdReg)); diff --git a/Instruction/AInstEmitSimdArithmetic.cs b/Instruction/AInstEmitSimdArithmetic.cs index 559811d..02e903f 100644 --- a/Instruction/AInstEmitSimdArithmetic.cs +++ b/Instruction/AInstEmitSimdArithmetic.cs @@ -158,6 +158,42 @@ namespace ChocolArm64.Instruction Context.MarkLabel(LblTrue); } + private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx Context, bool Round) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int ESize = 8 << Op.Size; + + Context.Emit(OpCodes.Mul); + + if (!Round) + { + Context.EmitAsr(ESize - 1); + } + else + { + long RoundConst = 1L << (ESize - 1); + + AILLabel LblTrue = new AILLabel(); + + Context.EmitLsl(1); + + Context.EmitLdc_I8(RoundConst); + + Context.Emit(OpCodes.Add); + + Context.EmitAsr(ESize); + + Context.Emit(OpCodes.Dup); + Context.EmitLdc_I8((long)int.MinValue); + Context.Emit(OpCodes.Bne_Un_S, LblTrue); + + Context.Emit(OpCodes.Neg); + + Context.MarkLabel(LblTrue); + } + } + private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round) { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; @@ -1040,6 +1076,16 @@ namespace ChocolArm64.Instruction EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Add); } + public static void Sqdmulh_S(AILEmitterCtx Context) + { + EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.ScalarSx); + } + + public static void Sqdmulh_V(AILEmitterCtx Context) + { + EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.VectorSx); + } + public static void Sqneg_S(AILEmitterCtx Context) { EmitScalarSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); @@ -1050,6 +1096,16 @@ namespace ChocolArm64.Instruction EmitVectorSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg)); } + public static void Sqrdmulh_S(AILEmitterCtx Context) + { + EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.ScalarSx); + } + + public static void Sqrdmulh_V(AILEmitterCtx Context) + { + EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.VectorSx); + } + public static void Sqsub_S(AILEmitterCtx Context) { EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Sub); diff --git a/Instruction/AInstEmitSimdHelper.cs b/Instruction/AInstEmitSimdHelper.cs index 161c44e..a9af390 100644 --- a/Instruction/AInstEmitSimdHelper.cs +++ b/Instruction/AInstEmitSimdHelper.cs @@ -804,7 +804,7 @@ namespace ChocolArm64.Instruction ScalarZx = Scalar, VectorSx = Signed, - VectorZx = 0, + VectorZx = 0 } public static void EmitScalarSaturatingUnaryOpSx(AILEmitterCtx Context, Action Emit) @@ -837,7 +837,14 @@ namespace ChocolArm64.Instruction Emit(); - EmitUnarySignedSatQAbsOrNeg(Context, Op.Size); + if (Op.Size <= 2) + { + EmitSatQ(Context, Op.Size, true, true); + } + else /* if (Op.Size == 3) */ + { + EmitUnarySignedSatQAbsOrNeg(Context); + } EmitVectorInsertTmp(Context, Index, Op.Size); } @@ -853,25 +860,25 @@ namespace ChocolArm64.Instruction public static void EmitScalarSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags) { - EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarSx | Flags); + EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.ScalarSx | Flags); } public static void EmitScalarSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags) { - EmitSaturatingBinaryOp(Context, SaturatingFlags.ScalarZx | Flags); + EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.ScalarZx | Flags); } public static void EmitVectorSaturatingBinaryOpSx(AILEmitterCtx Context, SaturatingFlags Flags) { - EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorSx | Flags); + EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.VectorSx | Flags); } public static void EmitVectorSaturatingBinaryOpZx(AILEmitterCtx Context, SaturatingFlags Flags) { - EmitSaturatingBinaryOp(Context, SaturatingFlags.VectorZx | Flags); + EmitSaturatingBinaryOp(Context, () => { }, SaturatingFlags.VectorZx | Flags); } - public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, SaturatingFlags Flags) + public static void EmitSaturatingBinaryOp(AILEmitterCtx Context, Action Emit, SaturatingFlags Flags) { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; @@ -940,6 +947,20 @@ namespace ChocolArm64.Instruction 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); @@ -1080,29 +1101,17 @@ namespace ChocolArm64.Instruction } } - // TSrc (8bit, 16bit, 32bit, 64bit) == TDst (8bit, 16bit, 32bit, 64bit); signed. - public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context, int Size) + // TSrc (64bit) == TDst (64bit); signed. + public static void EmitUnarySignedSatQAbsOrNeg(AILEmitterCtx Context) { - int ESize = 8 << Size; + if (((AOpCodeSimd)Context.CurrOp).Size < 3) + { + throw new InvalidOperationException(); + } - long TMaxValue = (1L << (ESize - 1)) - 1L; - long TMinValue = -(1L << (ESize - 1)); + Context.EmitLdarg(ATranslatedSub.StateArgIdx); - AILLabel LblFalse = new AILLabel(); - - Context.Emit(OpCodes.Dup); - Context.Emit(OpCodes.Neg); - Context.EmitLdc_I8(TMinValue); - Context.Emit(OpCodes.Ceq); - Context.Emit(OpCodes.Brfalse_S, LblFalse); - - Context.Emit(OpCodes.Pop); - - EmitSetFpsrQCFlag(Context); - - Context.EmitLdc_I8(TMaxValue); - - Context.MarkLabel(LblFalse); + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UnarySignedSatQAbsOrNeg)); } // TSrcs (64bit) == TDst (64bit); signed, unsigned. @@ -1150,22 +1159,6 @@ namespace ChocolArm64.Instruction : nameof(ASoftFallback.BinaryUnsignedSatQAcc)); } - public static void EmitSetFpsrQCFlag(AILEmitterCtx Context) - { - const int QCFlagBit = 27; - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - - Context.EmitLdarg(ATranslatedSub.StateArgIdx); - Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr)); - - Context.EmitLdc_I4(1 << QCFlagBit); - - Context.Emit(OpCodes.Or); - - Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr)); - } - public static void EmitScalarSet(AILEmitterCtx Context, int Reg, int Size) { EmitVectorZeroAll(Context, Reg); diff --git a/Instruction/ASoftFallback.cs b/Instruction/ASoftFallback.cs index a4d12dd..4089857 100644 --- a/Instruction/ASoftFallback.cs +++ b/Instruction/ASoftFallback.cs @@ -11,6 +11,107 @@ namespace ChocolArm64.Instruction Context.EmitCall(typeof(ASoftFallback), MthdName); } +#region "Saturating" + public static long SignedSrcSignedDstSatQ(long op, int Size, AThreadState State) + { + int ESize = 8 << Size; + + long TMaxValue = (1L << (ESize - 1)) - 1L; + long TMinValue = -(1L << (ESize - 1)); + + if (op > TMaxValue) + { + SetFpsrQCFlag(State); + + return TMaxValue; + } + else if (op < TMinValue) + { + SetFpsrQCFlag(State); + + return TMinValue; + } + else + { + return op; + } + } + + public static ulong SignedSrcUnsignedDstSatQ(long op, int Size, AThreadState State) + { + int ESize = 8 << Size; + + ulong TMaxValue = (1UL << ESize) - 1UL; + ulong TMinValue = 0UL; + + if (op > (long)TMaxValue) + { + SetFpsrQCFlag(State); + + return TMaxValue; + } + else if (op < (long)TMinValue) + { + SetFpsrQCFlag(State); + + return TMinValue; + } + else + { + return (ulong)op; + } + } + + public static long UnsignedSrcSignedDstSatQ(ulong op, int Size, AThreadState State) + { + int ESize = 8 << Size; + + long TMaxValue = (1L << (ESize - 1)) - 1L; + + if (op > (ulong)TMaxValue) + { + SetFpsrQCFlag(State); + + return TMaxValue; + } + else + { + return (long)op; + } + } + + public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int Size, AThreadState State) + { + int ESize = 8 << Size; + + ulong TMaxValue = (1UL << ESize) - 1UL; + + if (op > TMaxValue) + { + SetFpsrQCFlag(State); + + return TMaxValue; + } + else + { + return op; + } + } + + public static long UnarySignedSatQAbsOrNeg(long op, AThreadState State) + { + if (op == long.MinValue) + { + SetFpsrQCFlag(State); + + return long.MaxValue; + } + else + { + return op; + } + } + public static long BinarySignedSatQAdd(long op1, long op2, AThreadState State) { long Add = op1 + op2; @@ -185,99 +286,15 @@ namespace ChocolArm64.Instruction } } - public static long SignedSrcSignedDstSatQ(long op, int Size, AThreadState State) - { - int ESize = 8 << Size; - - long TMaxValue = (1L << (ESize - 1)) - 1L; - long TMinValue = -(1L << (ESize - 1)); - - if (op > TMaxValue) - { - SetFpsrQCFlag(State); - - return TMaxValue; - } - else if (op < TMinValue) - { - SetFpsrQCFlag(State); - - return TMinValue; - } - else - { - return op; - } - } - - public static ulong SignedSrcUnsignedDstSatQ(long op, int Size, AThreadState State) - { - int ESize = 8 << Size; - - ulong TMaxValue = (1UL << ESize) - 1UL; - ulong TMinValue = 0UL; - - if (op > (long)TMaxValue) - { - SetFpsrQCFlag(State); - - return TMaxValue; - } - else if (op < (long)TMinValue) - { - SetFpsrQCFlag(State); - - return TMinValue; - } - else - { - return (ulong)op; - } - } - - public static long UnsignedSrcSignedDstSatQ(ulong op, int Size, AThreadState State) - { - int ESize = 8 << Size; - - long TMaxValue = (1L << (ESize - 1)) - 1L; - - if (op > (ulong)TMaxValue) - { - SetFpsrQCFlag(State); - - return TMaxValue; - } - else - { - return (long)op; - } - } - - public static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int Size, AThreadState State) - { - int ESize = 8 << Size; - - ulong TMaxValue = (1UL << ESize) - 1UL; - - if (op > TMaxValue) - { - SetFpsrQCFlag(State); - - return TMaxValue; - } - else - { - return op; - } - } - private static void SetFpsrQCFlag(AThreadState State) { const int QCFlagBit = 27; State.Fpsr |= 1 << QCFlagBit; } +#endregion +#region "Count" public static ulong CountLeadingSigns(ulong Value, int Size) { Value ^= Value >> 1; @@ -325,7 +342,9 @@ namespace ChocolArm64.Instruction return (Value >> 4) + (Value & 0x0f); } +#endregion +#region "Crc32" private const uint Crc32RevPoly = 0xedb88320; private const uint Crc32cRevPoly = 0x82f63b78; @@ -384,7 +403,9 @@ namespace ChocolArm64.Instruction return Crc; } +#endregion +#region "Reverse" public static uint ReverseBits8(uint Value) { Value = ((Value & 0xaa) >> 1) | ((Value & 0x55) << 1); @@ -453,7 +474,9 @@ namespace ChocolArm64.Instruction throw new ArgumentException(nameof(Size)); } +#endregion +#region "MultiplyHigh" public static long SMulHi128(long LHS, long RHS) { long Result = (long)UMulHi128((ulong)LHS, (ulong)RHS); @@ -479,5 +502,6 @@ namespace ChocolArm64.Instruction return LHigh * RHigh + Z0 + (Z1 >> 32); } +#endregion } }