From b0368079fbabef7acfb32f5e21bbcb23f27a4f74 Mon Sep 17 00:00:00 2001 From: MS-DOS1999 Date: Thu, 19 Apr 2018 05:22:12 +0200 Subject: [PATCH] Fix Fmin/max and add vector version, add and modifying fmin/max tests (#89) --- AOpCodeTable.cs | 2 + Instruction/AInstEmitSimdArithmetic.cs | 80 ++++++++++++++++++++++++-- Instruction/ASoftFallback.cs | 76 ++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 4 deletions(-) diff --git a/AOpCodeTable.cs b/AOpCodeTable.cs index d4cbd6f..fb74f89 100644 --- a/AOpCodeTable.cs +++ b/AOpCodeTable.cs @@ -211,8 +211,10 @@ namespace ChocolArm64 Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg)); Set("000111110x0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg)); Set("000111100x1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg)); + Set("0x0011100x1xxxxx111101xxxxxxxxxx", AInstEmit.Fmax_V, typeof(AOpCodeSimdReg)); Set("000111100x1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg)); Set("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg)); + Set("0x0011101x1xxxxx111101xxxxxxxxxx", AInstEmit.Fmin_V, typeof(AOpCodeSimdReg)); Set("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg)); Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg)); Set("0x0011111< { - EmitBinaryMathCall(Context, nameof(Math.Max)); + if (Op.Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MaxF)); + } + else if (Op.Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Max)); + } + else + { + throw new InvalidOperationException(); + } + }); + } + + public static void Fmax_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + EmitVectorBinaryOpF(Context, () => + { + if (Op.Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MaxF)); + } + else if (Op.Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Max)); + } + else + { + throw new InvalidOperationException(); + } }); } public static void Fmin_S(AILEmitterCtx Context) { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + EmitScalarBinaryOpF(Context, () => { - EmitBinaryMathCall(Context, nameof(Math.Min)); + if (Op.Size == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MinF)); + } + else if (Op.Size == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Min)); + } + else + { + throw new InvalidOperationException(); + } + }); + } + + public static void Fmin_V(AILEmitterCtx Context) + { + AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + + int SizeF = Op.Size & 1; + + EmitVectorBinaryOpF(Context, () => + { + if (SizeF == 0) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MinF)); + } + else if (SizeF == 1) + { + ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Min)); + } + else + { + throw new InvalidOperationException(); + } }); } @@ -510,17 +580,19 @@ namespace ChocolArm64.Instruction { AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp; + int SizeF = Op.Size & 1; + EmitVectorUnaryOpF(Context, () => { Context.EmitLdarg(ATranslatedSub.StateArgIdx); Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr)); - if (Op.Size == 2) + if (SizeF == 0) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF)); } - else if (Op.Size == 3) + else if (SizeF == 1) { ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round)); } diff --git a/Instruction/ASoftFallback.cs b/Instruction/ASoftFallback.cs index 64f539f..c08f253 100644 --- a/Instruction/ASoftFallback.cs +++ b/Instruction/ASoftFallback.cs @@ -256,6 +256,82 @@ namespace ChocolArm64.Instruction ((Value >> 6) & 1) + (Value >> 7); } + public static float MaxF(float val1, float val2) + { + if (val1 == 0.0 && val2 == 0.0) + { + if (BitConverter.SingleToInt32Bits(val1) < 0 && BitConverter.SingleToInt32Bits(val2) < 0) + return -0.0f; + + return 0.0f; + } + + if (val1 > val2) + return val1; + + if (float.IsNaN(val1)) + return val1; + + return val2; + } + + public static double Max(double val1, double val2) + { + if (val1 == 0.0 && val2 == 0.0) + { + if (BitConverter.DoubleToInt64Bits(val1) < 0 && BitConverter.DoubleToInt64Bits(val2) < 0) + return -0.0; + + return 0.0; + } + + if (val1 > val2) + return val1; + + if (double.IsNaN(val1)) + return val1; + + return val2; + } + + public static float MinF(float val1, float val2) + { + if (val1 == 0.0 && val2 == 0.0) + { + if (BitConverter.SingleToInt32Bits(val1) < 0 || BitConverter.SingleToInt32Bits(val2) < 0) + return -0.0f; + + return 0.0f; + } + + if (val1 < val2) + return val1; + + if (float.IsNaN(val1)) + return val1; + + return val2; + } + + public static double Min(double val1, double val2) + { + if (val1 == 0.0 && val2 == 0.0) + { + if (BitConverter.DoubleToInt64Bits(val1) < 0 || BitConverter.DoubleToInt64Bits(val2) < 0) + return -0.0; + + return 0.0; + } + + if (val1 < val2) + return val1; + + if (double.IsNaN(val1)) + return val1; + + return val2; + } + public static float RoundF(float Value, int Fpcr) { switch ((ARoundMode)((Fpcr >> 22) & 3))