Fix Fmin/max and add vector version, add and modifying fmin/max tests (#89)

This commit is contained in:
MS-DOS1999 2018-04-19 05:22:12 +02:00 committed by gdkchan
parent 5a383d86b1
commit b0368079fb
3 changed files with 154 additions and 4 deletions

View file

@ -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<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));

View file

@ -211,17 +211,87 @@ namespace ChocolArm64.Instruction
public static void Fmax_S(AILEmitterCtx Context)
{
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
EmitScalarBinaryOpF(Context, () =>
{
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));
}

View file

@ -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))