From 980d30325bf771cc585d5295ff256e712eab9206 Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Tue, 17 Jul 2018 16:24:17 +0200 Subject: [PATCH 1/8] SQADD/UQADD instructions --- ChocolArm64/AOpCodeTable.cs | 4 + .../Instruction/AInstEmitSimdArithmetic.cs | 20 ++++ .../Instruction/AInstEmitSimdHelper.cs | 109 ++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 0e979aa44f..3316784c9b 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -373,6 +373,8 @@ namespace ChocolArm64 SetA64("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V, typeof(AOpCodeSimdReg)); SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", AInstEmit.Smlsl_V, typeof(AOpCodeSimdReg)); SetA64("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg)); + SetA64("01011110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_S, typeof(AOpCodeSimdReg)); + SetA64("0x001110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_V, typeof(AOpCodeSimdReg)); SetA64("0x00111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_V, typeof(AOpCodeSimdShImm)); SetA64("01011110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_S, typeof(AOpCodeSimd)); SetA64("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V, typeof(AOpCodeSimd)); @@ -421,6 +423,8 @@ namespace ChocolArm64 SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", AInstEmit.Uminp_V, typeof(AOpCodeSimdReg)); SetA64("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg)); + SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S, typeof(AOpCodeSimdReg)); + SetA64("0x101110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_V, typeof(AOpCodeSimdReg)); SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd)); SetA64("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V, typeof(AOpCodeSimd)); SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs index 36bb1cbf16..67a5609ea0 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -1052,6 +1052,16 @@ namespace ChocolArm64.Instruction EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul)); } + public static void Sqadd_S(AILEmitterCtx Context) + { + EmitScalarSaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Sqadd_V(AILEmitterCtx Context) + { + EmitVectorSaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); + } + public static void Sqxtn_S(AILEmitterCtx Context) { EmitScalarSaturatingNarrowOpSxSx(Context, () => { }); @@ -1216,6 +1226,16 @@ namespace ChocolArm64.Instruction EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul)); } + public static void Uqadd_S(AILEmitterCtx Context) + { + EmitScalarSaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); + } + + public static void Uqadd_V(AILEmitterCtx Context) + { + EmitVectorSaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); + } + public static void Uqxtn_S(AILEmitterCtx Context) { EmitScalarSaturatingNarrowOpZxZx(Context, () => { }); diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index 7716e2987a..ae7be5efbe 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -773,6 +773,115 @@ namespace ChocolArm64.Instruction } } + public static void EmitScalarSaturatingOpSxSx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, true, true, true); + } + + public static void EmitScalarSaturatingOpSxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, true, false, true); + } + + public static void EmitScalarSaturatingOpZxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, false, false, true); + } + + public static void EmitVectorSaturatingOpSxSx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, true, true, false); + } + + public static void EmitVectorSaturatingOpSxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, true, false, false); + } + + public static void EmitVectorSaturatingOpZxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, false, false, false); + } + + public static void EmitSaturatingOp( + AILEmitterCtx Context, + Action Emit, + bool SignedSrc, + bool SignedDst, + bool Scalar) + { + AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + + int Elems = !Scalar ? 8 >> Op.Size : 1; + + int ESize = 8 << Op.Size; + + long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; + long 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); + EmitVectorExtract(Context, Op.Rm, 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, Index, Op.Size); + } + + Context.EmitLdvectmp(); + Context.EmitStvec(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 EmitScalarSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) { EmitSaturatingNarrowOp(Context, Emit, true, true, true); From 2d7606b89743758764db10bd9f7f69cc85fa50ac Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Thu, 19 Jul 2018 23:18:21 +0200 Subject: [PATCH 2/8] save before merge --- ChocolArm64/AOpCodeTable.cs | 4 ++-- ChocolArm64/Instruction/AInstEmitSimdHelper.cs | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ChocolArm64/AOpCodeTable.cs b/ChocolArm64/AOpCodeTable.cs index 3316784c9b..e90d555300 100644 --- a/ChocolArm64/AOpCodeTable.cs +++ b/ChocolArm64/AOpCodeTable.cs @@ -374,7 +374,7 @@ namespace ChocolArm64 SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", AInstEmit.Smlsl_V, typeof(AOpCodeSimdReg)); SetA64("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg)); SetA64("01011110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_S, typeof(AOpCodeSimdReg)); - SetA64("0x001110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_V, typeof(AOpCodeSimdReg)); + SetA64("0>001110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Sqadd_V, typeof(AOpCodeSimdReg)); SetA64("0x00111100>>>xxx100111xxxxxxxxxx", AInstEmit.Sqrshrn_V, typeof(AOpCodeSimdShImm)); SetA64("01011110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_S, typeof(AOpCodeSimd)); SetA64("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V, typeof(AOpCodeSimd)); @@ -424,7 +424,7 @@ namespace ChocolArm64 SetA64("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns)); SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg)); SetA64("01111110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_S, typeof(AOpCodeSimdReg)); - SetA64("0x101110xx1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_V, typeof(AOpCodeSimdReg)); + SetA64("0>101110<<1xxxxx000011xxxxxxxxxx", AInstEmit.Uqadd_V, typeof(AOpCodeSimdReg)); SetA64("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd)); SetA64("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V, typeof(AOpCodeSimd)); SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg)); diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index ae7be5efbe..67bfdc5449 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -812,11 +812,12 @@ namespace ChocolArm64.Instruction { AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; - int Elems = !Scalar ? 8 >> Op.Size : 1; + int Bytes = Op.GetBitsCount() >> 3; + int Elems = !Scalar ? Bytes >> Op.Size : 1; int ESize = 8 << Op.Size; - long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; + long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize)); long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0; Context.EmitLdc_I8(0L); @@ -827,8 +828,8 @@ namespace ChocolArm64.Instruction AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); - EmitVectorExtract(Context, Op.Rm, Index, Op.Size + 1, SignedSrc); + EmitVectorExtract(Context, Op.Rn, Index, Op.Size, SignedSrc); + EmitVectorExtract(Context, Op.Rm, Index, Op.Size, SignedSrc); Emit(); @@ -862,9 +863,9 @@ namespace ChocolArm64.Instruction Context.MarkLabel(LblGeEnd); - if (Scalar) + if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar) { - EmitVectorZeroLower(Context, Op.Rd); + EmitVectorZeroUpper(Context, Op.Rd); } EmitVectorInsertTmp(Context, Index, Op.Size); From aa8b5acca61d699fcfd22188fdd95c66a04c9f9d Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 02:57:55 +0200 Subject: [PATCH 3/8] Merge Saturating Narrow and not Arrow, boolean to flags --- .../Instruction/AInstEmitSimdArithmetic.cs | 20 +- .../Instruction/AInstEmitSimdHelper.cs | 220 ++++++++---------- ChocolArm64/Instruction/AInstEmitSimdShift.cs | 2 +- 3 files changed, 102 insertions(+), 140 deletions(-) diff --git a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs index d78d41c7f6..fbe1c5342e 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdArithmetic.cs @@ -1054,32 +1054,32 @@ namespace ChocolArm64.Instruction public static void Sqadd_S(AILEmitterCtx Context) { - EmitScalarSaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); + EmitScalarBinarySaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); } public static void Sqadd_V(AILEmitterCtx Context) { - EmitVectorSaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); + EmitVectorBinarySaturatingOpSxSx(Context, () => Context.Emit(OpCodes.Add)); } public static void Sqxtn_S(AILEmitterCtx Context) { - EmitScalarSaturatingNarrowOpSxSx(Context, () => { }); + EmitScalarUnarySaturatingNarrowOpSxSx(Context, () => { }); } public static void Sqxtn_V(AILEmitterCtx Context) { - EmitVectorSaturatingNarrowOpSxSx(Context, () => { }); + EmitVectorUnarySaturatingNarrowOpSxSx(Context, () => { }); } public static void Sqxtun_S(AILEmitterCtx Context) { - EmitScalarSaturatingNarrowOpSxZx(Context, () => { }); + EmitScalarUnarySaturatingNarrowOpSxZx(Context, () => { }); } public static void Sqxtun_V(AILEmitterCtx Context) { - EmitVectorSaturatingNarrowOpSxZx(Context, () => { }); + EmitVectorUnarySaturatingNarrowOpSxZx(Context, () => { }); } public static void Ssubw_V(AILEmitterCtx Context) @@ -1233,22 +1233,22 @@ namespace ChocolArm64.Instruction public static void Uqadd_S(AILEmitterCtx Context) { - EmitScalarSaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); + EmitScalarBinarySaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); } public static void Uqadd_V(AILEmitterCtx Context) { - EmitVectorSaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); + EmitVectorBinarySaturatingOpZxZx(Context, () => Context.Emit(OpCodes.Add)); } public static void Uqxtn_S(AILEmitterCtx Context) { - EmitScalarSaturatingNarrowOpZxZx(Context, () => { }); + EmitScalarUnarySaturatingNarrowOpZxZx(Context, () => { }); } public static void Uqxtn_V(AILEmitterCtx Context) { - EmitVectorSaturatingNarrowOpZxZx(Context, () => { }); + EmitVectorUnarySaturatingNarrowOpZxZx(Context, () => { }); } public static void Usubw_V(AILEmitterCtx Context) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index f9074e0ac8..c3fdd71d45 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -781,168 +781,126 @@ namespace ChocolArm64.Instruction } } - public static void EmitScalarSaturatingOpSxSx(AILEmitterCtx Context, Action Emit) + [Flags] + public enum SaturatingFlags { - EmitSaturatingOp(Context, Emit, true, true, true); + None = 0, + + SignedSrc = 1 << 0, + SignedDst = 1 << 1, + Scalar = 1 << 2, + Narrow = 1 << 3, + Binary = 1 << 4, + + SxSxScalar = SignedSrc | SignedDst | Scalar, + SxSxScalarNarrow = SignedSrc | SignedDst | Scalar | Narrow, + SxZxScalar = SignedSrc | Scalar, + SxZxScalarNarrow = SignedSrc | Scalar | Narrow, + ZxZxScalar = Scalar, + ZxZxScalarNarrow = Scalar | Narrow, + + SxSxVector = SignedSrc | SignedDst, + SxSxVectorNarrow = SignedSrc | SignedDst | Narrow, + SxZxVector = SignedSrc, + SxZxVectorNarrow = SignedSrc | Narrow, + ZxZxVector = 0, + ZxZxVectorNarrow = Narrow, + + SxSxScalarBinary = SignedSrc | SignedDst | Scalar | Binary, + SxSxScalarNarrowBinary = SignedSrc | SignedDst | Scalar | Narrow | Binary, + SxZxScalarBinary = SignedSrc | Scalar | Binary, + SxZxScalarNarrowBinary = SignedSrc | Scalar | Narrow | Binary, + ZxZxScalarBinary = Scalar | Binary, + ZxZxScalarNarrowBinary = Scalar | Narrow | Binary, + + SxSxVectorBinary = SignedSrc | SignedDst | Binary, + SxSxVectorNarrowBinary = SignedSrc | SignedDst | Narrow | Binary, + SxZxVectorBinary = SignedSrc | Binary, + SxZxVectorNarrowBinary = SignedSrc | Narrow | Binary, + ZxZxVectorBinary = Binary, + ZxZxVectorNarrowBinary = Narrow | Binary } - public static void EmitScalarSaturatingOpSxZx(AILEmitterCtx Context, Action Emit) + public static void EmitScalarBinarySaturatingOpSxSx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, true, false, true); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxScalarBinary); } - public static void EmitScalarSaturatingOpZxZx(AILEmitterCtx Context, Action Emit) + public static void EmitScalarBinarySaturatingOpZxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, false, false, true); + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxScalarBinary); } - public static void EmitVectorSaturatingOpSxSx(AILEmitterCtx Context, Action Emit) + public static void EmitVectorBinarySaturatingOpSxSx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, true, true, false); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxVectorBinary); } - public static void EmitVectorSaturatingOpSxZx(AILEmitterCtx Context, Action Emit) + public static void EmitVectorBinarySaturatingOpZxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, true, false, false); + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxVectorBinary); } - public static void EmitVectorSaturatingOpZxZx(AILEmitterCtx Context, Action Emit) + public static void EmitScalarUnarySaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, false, false, false); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxScalarNarrow); + } + + public static void EmitScalarUnarySaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxScalarNarrow); + } + + public static void EmitScalarUnarySaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxScalarNarrow); + } + + public static void EmitVectorUnarySaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxVectorNarrow); + } + + public static void EmitVectorUnarySaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxVectorNarrow); + } + + public static void EmitVectorUnarySaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) + { + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxVectorNarrow); } public static void EmitSaturatingOp( AILEmitterCtx Context, Action Emit, - bool SignedSrc, - bool SignedDst, - bool Scalar) + SaturatingFlags Flags) { - AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp; + bool SignedSrc = (Flags & SaturatingFlags.SignedSrc) != 0; + bool SignedDst = (Flags & SaturatingFlags.SignedDst) != 0; + bool Scalar = (Flags & SaturatingFlags.Scalar) != 0; + bool Narrow = (Flags & SaturatingFlags.Narrow) != 0; + bool Binary = (Flags & SaturatingFlags.Binary) != 0; - int Bytes = Op.GetBitsCount() >> 3; - int Elems = !Scalar ? Bytes >> Op.Size : 1; - - int ESize = 8 << Op.Size; - - long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize)); - long 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, SignedSrc); - EmitVectorExtract(Context, Op.Rm, Index, Op.Size, 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 ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar) - { - EmitVectorZeroUpper(Context, Op.Rd); - } - - EmitVectorInsertTmp(Context, Index, Op.Size); - } - - Context.EmitLdvectmp(); - Context.EmitStvec(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 EmitScalarSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, true, true, true); - } - - public static void EmitScalarSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, true, false, true); - } - - public static void EmitScalarSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, false, false, true); - } - - public static void EmitVectorSaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, true, true, false); - } - - public static void EmitVectorSaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, true, false, false); - } - - public static void EmitVectorSaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) - { - EmitSaturatingNarrowOp(Context, Emit, false, false, false); - } - - 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; + int Part = 0; + if (Narrow) + { + Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; + } - long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize)); + 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) + if (Part != 0 && Narrow) { Context.EmitLdvec(Op.Rd); Context.EmitStvectmp(); @@ -954,6 +912,10 @@ namespace ChocolArm64.Instruction AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); + if (Binary) + { + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size + 1, SignedSrc); + } Emit(); @@ -992,13 +954,13 @@ namespace ChocolArm64.Instruction EmitVectorZeroLowerTmp(Context); } - EmitVectorInsertTmp(Context, Part + Index, Op.Size); + EmitVectorInsertTmp(Context, Narrow ? Index + Part : Index, Op.Size); } Context.EmitLdvectmp(); Context.EmitStvec(Op.Rd); - if (Part == 0) + if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar || (Part == 0 && Narrow)) { EmitVectorZeroUpper(Context, Op.Rd); } diff --git a/ChocolArm64/Instruction/AInstEmitSimdShift.cs b/ChocolArm64/Instruction/AInstEmitSimdShift.cs index 6f6b56068e..721b1c8eaf 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdShift.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdShift.cs @@ -100,7 +100,7 @@ namespace ChocolArm64.Instruction Context.Emit(OpCodes.Shr); }; - EmitVectorSaturatingNarrowOpSxSx(Context, Emit); + EmitVectorUnarySaturatingNarrowOpSxSx(Context, Emit); } public static void Srshr_V(AILEmitterCtx Context) From 29298192ec79e61471be8382b93a1ec3901ded25 Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 03:18:36 +0200 Subject: [PATCH 4/8] fix 'unary', newline --- .../Instruction/AInstEmitSimdHelper.cs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index c3fdd71d45..1b669547b9 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -792,19 +792,19 @@ namespace ChocolArm64.Instruction Narrow = 1 << 3, Binary = 1 << 4, - SxSxScalar = SignedSrc | SignedDst | Scalar, - SxSxScalarNarrow = SignedSrc | SignedDst | Scalar | Narrow, - SxZxScalar = SignedSrc | Scalar, - SxZxScalarNarrow = SignedSrc | Scalar | Narrow, - ZxZxScalar = Scalar, - ZxZxScalarNarrow = Scalar | Narrow, + SxSxScalarUnary = SignedSrc | SignedDst | Scalar, + SxSxScalarNarrowUnary = SignedSrc | SignedDst | Scalar | Narrow, + SxZxScalarUnary = SignedSrc | Scalar, + SxZxScalarNarrowUnary = SignedSrc | Scalar | Narrow, + ZxZxScalarUnary = Scalar, + ZxZxScalarNarrowUnary = Scalar | Narrow, - SxSxVector = SignedSrc | SignedDst, - SxSxVectorNarrow = SignedSrc | SignedDst | Narrow, - SxZxVector = SignedSrc, - SxZxVectorNarrow = SignedSrc | Narrow, - ZxZxVector = 0, - ZxZxVectorNarrow = Narrow, + SxSxVectorUnary = SignedSrc | SignedDst, + SxSxVectorNarrowUnary = SignedSrc | SignedDst | Narrow, + SxZxVectorUnary = SignedSrc, + SxZxVectorNarrowUnary = SignedSrc | Narrow, + ZxZxVectorUnary = 0, + ZxZxVectorNarrowUnary = Narrow, SxSxScalarBinary = SignedSrc | SignedDst | Scalar | Binary, SxSxScalarNarrowBinary = SignedSrc | SignedDst | Scalar | Narrow | Binary, @@ -843,32 +843,32 @@ namespace ChocolArm64.Instruction public static void EmitScalarUnarySaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxScalarNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxScalarNarrowUnary); } public static void EmitScalarUnarySaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxScalarNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxScalarNarrowUnary); } public static void EmitScalarUnarySaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxScalarNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxScalarNarrowUnary); } public static void EmitVectorUnarySaturatingNarrowOpSxSx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxVectorNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxSxVectorNarrowUnary); } public static void EmitVectorUnarySaturatingNarrowOpSxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxVectorNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.SxZxVectorNarrowUnary); } public static void EmitVectorUnarySaturatingNarrowOpZxZx(AILEmitterCtx Context, Action Emit) { - EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxVectorNarrow); + EmitSaturatingOp(Context, Emit, SaturatingFlags.ZxZxVectorNarrowUnary); } public static void EmitSaturatingOp( @@ -889,6 +889,7 @@ namespace ChocolArm64.Instruction int ESize = 8 << Op.Size; int Part = 0; + if (Narrow) { Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; @@ -912,6 +913,7 @@ namespace ChocolArm64.Instruction AILLabel LblGeEnd = new AILLabel(); EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); + if (Binary) { EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size + 1, SignedSrc); From 74f52b34a1ea834fc1656895e39e656493a578de Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 10:43:12 +0200 Subject: [PATCH 5/8] fix notNarrow VectorExtract, and add a tiny test to be sure that EmitSaturatingOp with notNarrow flag doesn't send errors --- ChocolArm64/Instruction/AInstEmitSimdHelper.cs | 8 +++++--- Ryujinx.Tests/Cpu/CpuTestSimd.cs | 13 +++++++++++++ Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index 1b669547b9..8d1cccd876 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -884,7 +884,9 @@ namespace ChocolArm64.Instruction AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; - int Elems = !Scalar ? 8 >> Op.Size : 1; + int Bytes = Op.GetBitsCount() >> 3; + + int Elems = !Scalar ? (Narrow ? 8 : Bytes) >> Op.Size : 1; int ESize = 8 << Op.Size; @@ -912,11 +914,11 @@ namespace ChocolArm64.Instruction AILLabel LblLe = new AILLabel(); AILLabel LblGeEnd = new AILLabel(); - EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc); + EmitVectorExtract(Context, Op.Rn, Index, Narrow ? Op.Size + 1 : Op.Size, SignedSrc); if (Binary) { - EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size + 1, SignedSrc); + EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Narrow ? Op.Size + 1 : Op.Size, SignedSrc); } Emit(); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index 82591edaee..08aa0fd348 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -1126,6 +1126,19 @@ namespace Ryujinx.Tests.Cpu }); } + [TestCase(0x00000001u, 0x7FFFFFFFu, 0x7FFFFFFFu, true)] + public void Sqadd_S(uint A, uint B, uint Result, bool Fpsr) + { + Vector128 V1 = MakeVectorE0(A); + Vector128 V2 = MakeVectorE0(B); + AThreadState ThreadState = SingleOpcode(0x5EA20C20, V1: V1, V2: V2); + Assert.Multiple(() => + { + Assert.AreEqual(Result, GetVectorE0(ThreadState.V0)); + Assert.AreEqual(((ThreadState.Fpsr >> 27) & 1) == 1, Fpsr); + }); + } + [Test, Description("SQXTN , ")] public void Sqxtn_S_HB_SH_DS([Values(0u)] uint Rd, [Values(1u, 0u)] uint Rn, diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs index 8e2d9a366e..b8d08fb3a7 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Tests.Cpu { public class CpuTestSimdArithmetic : CpuTest { + [TestCase(0x1E224820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000000000000ul)] [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] From f7d640375dae2087baa8a4bc3093d20c23d8563a Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 10:45:04 +0200 Subject: [PATCH 6/8] Update CpuTestSimdArithmetic.cs --- Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs index b8d08fb3a7..8e2d9a366e 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs @@ -9,7 +9,6 @@ namespace Ryujinx.Tests.Cpu { public class CpuTestSimdArithmetic : CpuTest { - [TestCase(0x1E224820u, 0x0000000000000000ul, 0x0000000080000000ul, 0x0000000000000000ul)] [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000000000000ul, 0x0000000000000000ul)] [TestCase(0x1E224820u, 0x0000000080000000ul, 0x0000000080000000ul, 0x0000000080000000ul)] From 45f169d0b075b53593a0561795a497d967fd13ce Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 11:16:23 +0200 Subject: [PATCH 7/8] one request changes forgotten --- ChocolArm64/Instruction/AInstEmitSimdHelper.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index 8d1cccd876..853df2f740 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -880,7 +880,7 @@ namespace ChocolArm64.Instruction bool SignedDst = (Flags & SaturatingFlags.SignedDst) != 0; bool Scalar = (Flags & SaturatingFlags.Scalar) != 0; bool Narrow = (Flags & SaturatingFlags.Narrow) != 0; - bool Binary = (Flags & SaturatingFlags.Binary) != 0; + bool Binary = (Flags & SaturatingFlags.Binary) != 0; AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; @@ -897,7 +897,8 @@ namespace ChocolArm64.Instruction Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; } - long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; + //long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; + long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize)); long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0; Context.EmitLdc_I8(0L); From a4a1a5011b0e5cb74643e76a6be343b256cd511d Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Fri, 20 Jul 2018 11:16:59 +0200 Subject: [PATCH 8/8] delete comment --- ChocolArm64/Instruction/AInstEmitSimdHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs index 853df2f740..22f356bc7b 100644 --- a/ChocolArm64/Instruction/AInstEmitSimdHelper.cs +++ b/ChocolArm64/Instruction/AInstEmitSimdHelper.cs @@ -897,7 +897,6 @@ namespace ChocolArm64.Instruction Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0; } - //long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (1L << ESize) - 1L; long TMaxValue = SignedDst ? (1 << (ESize - 1)) - 1 : (long)(~0UL >> (64 - ESize)); long TMinValue = SignedDst ? -((1 << (ESize - 1))) : 0;