diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs index 9a632fd63..a35e28a15 100644 --- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs +++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs @@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2); }); } } @@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2); }); } } @@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2); }); } } @@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions { EmitVectorAcrossVectorOpF(context, (op1, op2) => { - return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2); + return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2); }); } } @@ -1633,37 +1633,17 @@ namespace ARMeilleure.Instructions public static void Frinti_S(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - EmitScalarUnaryOpF(context, (op1) => { - if (op.Size == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (op.Size == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } public static void Frinti_V(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - EmitVectorUnaryOpF(context, (op1) => { - if (sizeF == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (sizeF == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } @@ -1759,37 +1739,17 @@ namespace ARMeilleure.Instructions public static void Frintx_S(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - EmitScalarUnaryOpF(context, (op1) => { - if (op.Size == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (op.Size == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } public static void Frintx_V(ArmEmitterContext context) { - OpCodeSimd op = (OpCodeSimd)context.CurrOp; - - int sizeF = op.Size & 1; - EmitVectorUnaryOpF(context, (op1) => { - if (sizeF == 0) - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1); - } - else /* if (sizeF == 1) */ - { - return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1); - } + return EmitRoundByRMode(context, op1); }); } diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs index 1acc74657..339d32939 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs @@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using ARMeilleure.Translation; using System; -using System.Reflection; using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.Instructions.InstEmitSimdHelper; @@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero) { - Operand one = Const(1); if (zero) { EmitVectorUnaryOpF32(context, (m) => { - OperandType type = m.Type; + Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f); - if (type == OperandType.FP64) - { - return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one); - } - else - { - return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one); - } + return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp); }); } else { EmitVectorBinaryOpF32(context, (n, m) => { - OperandType type = n.Type; - - if (type == OperandType.FP64) - { - return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one); - } - else - { - return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one); - } + return EmitSoftFloatCallDefaultFpscr(context, name, n, m); }); } } @@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions me = ExtractScalar(context, type, op.Vm); } - MethodInfo info = sizeF != 0 - ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)) - : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)); - - Operand nzcv = context.Call(info, ne, me, Const(signalNaNs)); + Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs)); EmitSetFpscrNzcv(context, nzcv); } diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs index 6994643ed..c8c427b79 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs @@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions { Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); + context.LoadFromContext(); res = context.ZeroExtend16(OperandType.I64, res); @@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); + context.LoadFromContext(); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } @@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions { Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne); + context.LoadFromContext(); res = context.ZeroExtend16(OperandType.I64, res); @@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1); + context.StoreToContext(); Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne); + context.LoadFromContext(); context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0)); } @@ -224,7 +232,9 @@ namespace ARMeilleure.Instructions { Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1); + context.StoreToContext(); Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne); + context.LoadFromContext(); res = context.VectorInsert(res, e, index); } @@ -333,7 +343,9 @@ namespace ARMeilleure.Instructions if (sizeF == 0) { + context.StoreToContext(); Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne); + context.LoadFromContext(); e = context.ZeroExtend16(OperandType.I64, e); diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index b06ddd5e7..69ba42747 100644 --- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions { Operand toConvert = ExtractScalar(context, floatSize, op.Vm); - Operand asInteger; - // TODO: Fast Path. if (roundWithFpscr) { - MethodInfo info; - - if (floatSize == OperandType.FP64) - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32)); - } - else - { - info = unsigned - ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32)) - : typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32)); - } - - asInteger = context.Call(info, toConvert); - } - else - { - // Round towards zero. - asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + toConvert = EmitRoundByRMode(context, toConvert); } + // Round towards zero. + Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + InsertScalar(context, op.Vd, asInteger); } } @@ -271,9 +252,7 @@ namespace ARMeilleure.Instructions break; } - Operand asInteger; - - asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); + Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned); InsertScalar(context, op.Vd, asInteger); } @@ -399,15 +378,9 @@ namespace ARMeilleure.Instructions // VRINTX (floating-point). public static void Vrintx_S(ArmEmitterContext context) { - OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - - bool doubleSize = (op.Size & 1) == 1; - string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF); - EmitScalarUnaryOpF32(context, (op1) => { - MethodInfo info = typeof(SoftFallback).GetMethod(methodName); - return context.Call(info, op1); + return EmitRoundByRMode(context, op1); }); } diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs index 27b5c1302..49c9e6879 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs @@ -361,6 +361,54 @@ namespace ARMeilleure.Instructions return context.Call(info, n, Const((int)roundMode)); } + public static Operand EmitGetRoundingMode(ArmEmitterContext context) + { + Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1)); + rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag)); + + return rMode; + } + + public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op) + { + Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64); + + Operand lbl1 = Label(); + Operand lbl2 = Label(); + Operand lbl3 = Label(); + Operand lblEnd = Label(); + + Operand rN = Const((int)FPRoundingMode.ToNearest); + Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity); + Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity); + + Operand res = context.AllocateLocal(op.Type); + + Operand rMode = EmitGetRoundingMode(context); + + context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual); + context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl1); + context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl2); + context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op)); + context.Branch(lblEnd); + + context.MarkLabel(lbl3); + context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs) { IOpCodeSimd op = (IOpCodeSimd)context.CurrOp; @@ -369,7 +417,11 @@ namespace ARMeilleure.Instructions ? typeof(SoftFloat32).GetMethod(name) : typeof(SoftFloat64).GetMethod(name); - return context.Call(info, callArgs); + context.StoreToContext(); + Operand res = context.Call(info, callArgs); + context.LoadFromContext(); + + return res; } public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit) @@ -1269,7 +1321,7 @@ namespace ARMeilleure.Instructions public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue) { - isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))); + isTrue = GetFpFlag(FPState.FzFlag); Operand lblTrue = Label(); context.BranchIfFalse(lblTrue, isTrue); @@ -1281,9 +1333,7 @@ namespace ARMeilleure.Instructions public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default) { - isTrue = isTrue == default - ? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))) - : isTrue; + isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue; Operand lblTrue = Label(); context.BranchIfFalse(lblTrue, isTrue); @@ -1533,31 +1583,90 @@ namespace ARMeilleure.Instructions context.Copy(d, res); } - // TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned). - // long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size); - public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst) + // long SignedSignSatQ(long op, int size); + public static Operand EmitSignedSignSatQ(ArmEmitterContext context, Operand op, int size) { - Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u); + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); Operand lbl1 = Label(); Operand lblEnd = Label(); - int eSize = 8 << sizeDst; + Operand zeroL = Const(0L); + Operand maxT = Const((1L << (eSize - 1)) - 1L); + Operand minT = Const(-(1L << (eSize - 1))); - Operand maxT = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL); - Operand minT = signedDst ? Const(-(1L << (eSize - 1))) : Const(0UL); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); - - context.BranchIf(lbl1, res, maxT, Comparison.LessOrEqual); + context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual); context.Copy(res, maxT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); - context.BranchIf(lblEnd, res, minT, Comparison.GreaterOrEqual); + context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual); context.Copy(res, minT); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + + // private static ulong UnsignedSignSatQ(ulong op, int size); + public static Operand EmitUnsignedSignSatQ(ArmEmitterContext context, Operand op, int size) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand lblEnd = Label(); + + Operand zeroUL = Const(0UL); + Operand maxT = Const(ulong.MaxValue >> (64 - eSize)); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL); + + context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI); + context.Copy(res, maxT); + SetFpFlag(context, FPState.QcFlag, Const(1)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + + // TSrc (16bit, 32bit, 64bit; signed) > TDst (8bit, 16bit, 32bit; signed, unsigned). + // long SignedSrcSignedDstSatQ(long op, int size); ulong SignedSrcUnsignedDstSatQ(long op, int size); + public static Operand EmitSignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst) + { + int eSizeDst = 8 << sizeDst; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32); + + Operand lbl1 = Label(); + Operand lblEnd = Label(); + + Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL); + Operand minT = signedDst ? Const(-(1L << (eSizeDst - 1))) : Const(0UL); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); + + context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual); + context.Copy(res, maxT); + SetFpFlag(context, FPState.QcFlag, Const(1)); + context.Branch(lblEnd); + + context.MarkLabel(lbl1); + context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual); + context.Copy(res, minT); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1569,19 +1678,20 @@ namespace ARMeilleure.Instructions // long UnsignedSrcSignedDstSatQ(ulong op, int size); ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size); public static Operand EmitUnsignedSrcSatQ(ArmEmitterContext context, Operand op, int sizeDst, bool signedDst) { - Debug.Assert(op.Type == OperandType.I64 && (uint)sizeDst <= 2u); + int eSizeDst = 8 << sizeDst; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSizeDst == 8 || eSizeDst == 16 || eSizeDst == 32); Operand lblEnd = Label(); - int eSize = 8 << sizeDst; - - Operand maxL = signedDst ? Const((1L << (eSize - 1)) - 1L) : Const((1UL << eSize) - 1UL); + Operand maxT = signedDst ? Const((1L << (eSizeDst - 1)) - 1L) : Const((1UL << eSizeDst) - 1UL); Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); - context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI); - context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI); + context.Copy(res, maxT); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1601,9 +1711,9 @@ namespace ARMeilleure.Instructions Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); - context.BranchIf(lblEnd, res, minL, Comparison.NotEqual); + context.BranchIf(lblEnd, op, minL, Comparison.NotEqual); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1620,17 +1730,18 @@ namespace ARMeilleure.Instructions Operand minL = Const(long.MinValue); Operand maxL = Const(long.MaxValue); - Operand zero = Const(0L); + Operand zeroL = Const(0L); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2)); + Operand add = context.Add(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add); Operand left = context.BitwiseNot(context.BitwiseExclusiveOr(op1, op2)); - Operand right = context.BitwiseExclusiveOr(op1, res); - context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual); + Operand right = context.BitwiseExclusiveOr(op1, add); + context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual); - Operand isPositive = context.ICompareGreaterOrEqual(op1, zero); + Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1647,11 +1758,12 @@ namespace ARMeilleure.Instructions Operand maxUL = Const(ulong.MaxValue); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2)); + Operand add = context.Add(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add); - context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI); + context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.Copy(res, maxUL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1668,17 +1780,18 @@ namespace ARMeilleure.Instructions Operand minL = Const(long.MinValue); Operand maxL = Const(long.MaxValue); - Operand zero = Const(0L); + Operand zeroL = Const(0L); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2)); + Operand sub = context.Subtract(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub); Operand left = context.BitwiseExclusiveOr(op1, op2); - Operand right = context.BitwiseExclusiveOr(op1, res); - context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zero, Comparison.GreaterOrEqual); + Operand right = context.BitwiseExclusiveOr(op1, sub); + context.BranchIf(lblEnd, context.BitwiseAnd(left, right), zeroL, Comparison.GreaterOrEqual); - Operand isPositive = context.ICompareGreaterOrEqual(op1, zero); + Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL); context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1693,13 +1806,14 @@ namespace ARMeilleure.Instructions Operand lblEnd = Label(); - Operand zero = Const(0L); + Operand zeroL = Const(0L); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Subtract(op1, op2)); + Operand sub = context.Subtract(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sub); context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI); - context.Copy(res, zero); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + context.Copy(res, zeroL); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1717,27 +1831,28 @@ namespace ARMeilleure.Instructions Operand lblEnd = Label(); Operand maxL = Const(long.MaxValue); - Operand zero = Const(0L); + Operand zeroL = Const(0L); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2)); + Operand add = context.Add(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add); context.BranchIf(lbl1, op1, maxL, Comparison.GreaterUI); - Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), res); - context.BranchIf(lblEnd, notOp2AndRes, zero, Comparison.GreaterOrEqual); + Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add); + context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); - context.BranchIf(lbl2, op2, zero, Comparison.Less); + context.BranchIf(lbl2, op2, zeroL, Comparison.Less); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl2); - context.BranchIf(lblEnd, res, maxL, Comparison.LessOrEqualUI); + context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI); context.Copy(res, maxL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); @@ -1755,21 +1870,22 @@ namespace ARMeilleure.Instructions Operand maxUL = Const(ulong.MaxValue); Operand maxL = Const(long.MaxValue); - Operand zero = Const(0L); + Operand zeroL = Const(0L); - Operand res = context.Copy(context.AllocateLocal(OperandType.I64), context.Add(op1, op2)); + Operand add = context.Add(op1, op2); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), add); - context.BranchIf(lbl1, op1, zero, Comparison.Less); - context.BranchIf(lblEnd, res, op1, Comparison.GreaterOrEqualUI); + context.BranchIf(lbl1, op1, zeroL, Comparison.Less); + context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI); context.Copy(res, maxUL); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lbl1); context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI); - context.BranchIf(lblEnd, res, zero, Comparison.GreaterOrEqual); - context.Copy(res, zero); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual); + context.Copy(res, zeroL); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.Branch(lblEnd); context.MarkLabel(lblEnd); diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index c530985fa..0620ea332 100644 --- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -1181,7 +1181,11 @@ namespace ARMeilleure.Instructions Array.Resize(ref callArgs, callArgs.Length + 1); callArgs[callArgs.Length - 1] = Const(1); - return context.Call(info, callArgs); + context.StoreToContext(); + Operand res = context.Call(info, callArgs); + context.LoadFromContext(); + + return res; } public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size) diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs index 1a95200db..146aeafa7 100644 --- a/ARMeilleure/Instructions/InstEmitSimdShift.cs +++ b/ARMeilleure/Instructions/InstEmitSimdShift.cs @@ -188,23 +188,7 @@ namespace ARMeilleure.Instructions public static void Sqrshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(1), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round | ShlRegFlags.Saturating); } public static void Sqrshrn_S(ArmEmitterContext context) @@ -229,23 +213,7 @@ namespace ARMeilleure.Instructions public static void Sqshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(0), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Saturating); } public static void Sqshrn_S(ArmEmitterContext context) @@ -280,23 +248,7 @@ namespace ARMeilleure.Instructions public static void Srshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(1), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Signed | ShlRegFlags.Round); } public static void Srshr_S(ArmEmitterContext context) @@ -393,12 +345,12 @@ namespace ARMeilleure.Instructions public static void Sshl_S(ArmEmitterContext context) { - EmitSshlOrUshl(context, signed: true, scalar: true); + EmitShlRegOp(context, ShlRegFlags.Scalar | ShlRegFlags.Signed); } public static void Sshl_V(ArmEmitterContext context) { - EmitSshlOrUshl(context, signed: true, scalar: false); + EmitShlRegOp(context, ShlRegFlags.Signed); } public static void Sshll_V(ArmEmitterContext context) @@ -506,23 +458,7 @@ namespace ARMeilleure.Instructions public static void Uqrshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(1), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Round | ShlRegFlags.Saturating); } public static void Uqrshrn_S(ArmEmitterContext context) @@ -537,23 +473,7 @@ namespace ARMeilleure.Instructions public static void Uqshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(0), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Saturating); } public static void Uqshrn_S(ArmEmitterContext context) @@ -568,23 +488,7 @@ namespace ARMeilleure.Instructions public static void Urshl_V(ArmEmitterContext context) { - OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; - - Operand res = context.VectorZero(); - - int elems = op.GetBytesCount() >> op.Size; - - for (int index = 0; index < elems; index++) - { - Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size); - Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size); - - Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)), ne, me, Const(1), Const(op.Size)); - - res = EmitVectorInsert(context, res, e, index, op.Size); - } - - context.Copy(GetVec(op.Rd), res); + EmitShlRegOp(context, ShlRegFlags.Round); } public static void Urshr_S(ArmEmitterContext context) @@ -677,12 +581,12 @@ namespace ARMeilleure.Instructions public static void Ushl_S(ArmEmitterContext context) { - EmitSshlOrUshl(context, signed: false, scalar: true); + EmitShlRegOp(context, ShlRegFlags.Scalar); } public static void Ushl_V(ArmEmitterContext context) { - EmitSshlOrUshl(context, signed: false, scalar: false); + EmitShlRegOp(context, ShlRegFlags.None); } public static void Ushll_V(ArmEmitterContext context) @@ -872,43 +776,6 @@ namespace ARMeilleure.Instructions context.Copy(GetVec(op.Rd), res); } - private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool signed) - { - Debug.Assert(op.Type == OperandType.I64); - Debug.Assert(shiftLsB.Type == OperandType.I32); - Debug.Assert((uint)size < 4u); - - Operand negShiftLsB = context.Negate(shiftLsB); - - Operand isInRange = context.BitwiseAnd( - context.ICompareLess(shiftLsB, Const(8 << size)), - context.ICompareLess(negShiftLsB, Const(8 << size))); - - Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0)); - - Operand shl = context.ShiftLeft(op, shiftLsB); - - Operand sarOrShr = signed - ? context.ShiftRightSI(op, negShiftLsB) - : context.ShiftRightUI(op, negShiftLsB); - - Operand res = context.ConditionalSelect(isPositive, shl, sarOrShr); - - if (signed) - { - Operand isPositive2 = context.ICompareGreaterOrEqual(op, Const(0L)); - - Operand res2 = context.ConditionalSelect(isPositive2, Const(0L), Const(-1L)); - res2 = context.ConditionalSelect(isPositive, Const(0L), res2); - - return context.ConditionalSelect(isInRange, res, res2); - } - else - { - return context.ConditionalSelect(isInRange, res, Const(0UL)); - } - } - private static void EmitVectorShrImmNarrowOpZx(ArmEmitterContext context, bool round) { OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; @@ -1168,8 +1035,23 @@ namespace ARMeilleure.Instructions } } - private static void EmitSshlOrUshl(ArmEmitterContext context, bool signed, bool scalar) + [Flags] + private enum ShlRegFlags { + None = 0, + Scalar = 1 << 0, + Signed = 1 << 1, + Round = 1 << 2, + Saturating = 1 << 3 + } + + private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None) + { + bool scalar = flags.HasFlag(ShlRegFlags.Scalar); + bool signed = flags.HasFlag(ShlRegFlags.Signed); + bool round = flags.HasFlag(ShlRegFlags.Round); + bool saturating = flags.HasFlag(ShlRegFlags.Saturating); + OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; Operand res = context.VectorZero(); @@ -1178,15 +1060,225 @@ namespace ARMeilleure.Instructions for (int index = 0; index < elems; index++) { - Operand ne = EmitVectorExtract (context, op.Rn, index, op.Size, signed); - Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, 0); + Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed); + Operand me = EmitVectorExtractSx(context, op.Rm, index << op.Size, size: 0); - Operand e = EmitShlRegOp(context, ne, context.ConvertI64ToI32(me), op.Size, signed); + Operand e = !saturating + ? EmitShlReg(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed) + : EmitShlRegSatQ(context, ne, context.ConvertI64ToI32(me), round, op.Size, signed); res = EmitVectorInsert(context, res, e, index, op.Size); } context.Copy(GetVec(op.Rd), res); } + + // long SignedShlReg(long op, int shiftLsB, bool round, int size); + // ulong UnsignedShlReg(ulong op, int shiftLsB, bool round, int size); + private static Operand EmitShlReg(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(shiftLsB.Type == OperandType.I32); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand lbl1 = Label(); + Operand lblEnd = Label(); + + Operand eSizeOp = Const(eSize); + Operand zero = Const(0); + Operand zeroL = Const(0L); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); + + context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual); + context.Copy(res, signed + ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize) + : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)); + context.Branch(lblEnd); + + context.MarkLabel(lbl1); + context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual); + Operand shl = context.ShiftLeft(op, shiftLsB); + Operand isGreaterOrEqual = context.ICompareGreaterOrEqual(shiftLsB, eSizeOp); + context.Copy(res, context.ConditionalSelect(isGreaterOrEqual, zeroL, shl)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + + // long SignedShlRegSatQ(long op, int shiftLsB, bool round, int size); + // ulong UnsignedShlRegSatQ(ulong op, int shiftLsB, bool round, int size); + private static Operand EmitShlRegSatQ(ArmEmitterContext context, Operand op, Operand shiftLsB, bool round, int size, bool signed) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(shiftLsB.Type == OperandType.I32); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand lbl1 = Label(); + Operand lbl2 = Label(); + Operand lblEnd = Label(); + + Operand eSizeOp = Const(eSize); + Operand zero = Const(0); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); + + context.BranchIf(lbl1, shiftLsB, zero, Comparison.GreaterOrEqual); + context.Copy(res, signed + ? EmitSignedShrReg(context, op, context.Negate(shiftLsB), round, eSize) + : EmitUnsignedShrReg(context, op, context.Negate(shiftLsB), round, eSize)); + context.Branch(lblEnd); + + context.MarkLabel(lbl1); + context.BranchIf(lblEnd, shiftLsB, zero, Comparison.LessOrEqual); + context.BranchIf(lbl2, shiftLsB, eSizeOp, Comparison.Less); + context.Copy(res, signed + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + context.Branch(lblEnd); + + context.MarkLabel(lbl2); + Operand shl = context.ShiftLeft(op, shiftLsB); + if (eSize == 64) + { + Operand sarOrShr = signed + ? context.ShiftRightSI(shl, shiftLsB) + : context.ShiftRightUI(shl, shiftLsB); + context.Copy(res, shl); + context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal); + context.Copy(res, signed + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + } + else + { + context.Copy(res, signed + ? EmitSignedSrcSatQ(context, shl, size, signedDst: true) + : EmitUnsignedSrcSatQ(context, shl, size, signedDst: false)); + } + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + + // shift := [1, 128]; eSize := {8, 16, 32, 64}. + // long SignedShrReg(long op, int shift, bool round, int eSize); + private static Operand EmitSignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize) + { + if (round) + { + Operand lblEnd = Label(); + + Operand eSizeOp = Const(eSize); + Operand zeroL = Const(0L); + Operand one = Const(1); + Operand oneL = Const(1L); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroL); + + context.BranchIf(lblEnd, shift, eSizeOp, Comparison.GreaterOrEqual); + Operand roundConst = context.ShiftLeft(oneL, context.Subtract(shift, one)); + Operand add = context.Add(op, roundConst); + Operand sar = context.ShiftRightSI(add, shift); + if (eSize == 64) + { + Operand shr = context.ShiftRightUI(add, shift); + Operand left = context.BitwiseAnd(context.Negate(op), context.BitwiseExclusiveOr(op, add)); + Operand isLess = context.ICompareLess(left, zeroL); + context.Copy(res, context.ConditionalSelect(isLess, shr, sar)); + } + else + { + context.Copy(res, sar); + } + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + else + { + Operand lblEnd = Label(); + + Operand eSizeOp = Const(eSize); + Operand zeroL = Const(0L); + Operand negOneL = Const(-1L); + + Operand sar = context.ShiftRightSI(op, shift); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), sar); + + context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less); + Operand isLess = context.ICompareLess(op, zeroL); + context.Copy(res, context.ConditionalSelect(isLess, negOneL, zeroL)); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + } + + // shift := [1, 128]; eSize := {8, 16, 32, 64}. + // ulong UnsignedShrReg(ulong op, int shift, bool round, int eSize); + private static Operand EmitUnsignedShrReg(ArmEmitterContext context, Operand op, Operand shift, bool round, int eSize) + { + if (round) + { + Operand lblEnd = Label(); + + Operand zeroUL = Const(0UL); + Operand one = Const(1); + Operand oneUL = Const(1UL); + Operand eSizeMaxOp = Const(64); + Operand oneShl63UL = Const(1UL << 63); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), zeroUL); + + context.BranchIf(lblEnd, shift, eSizeMaxOp, Comparison.Greater); + Operand roundConst = context.ShiftLeft(oneUL, context.Subtract(shift, one)); + Operand add = context.Add(op, roundConst); + Operand shr = context.ShiftRightUI(add, shift); + Operand isEqual = context.ICompareEqual(shift, eSizeMaxOp); + context.Copy(res, context.ConditionalSelect(isEqual, zeroUL, shr)); + if (eSize == 64) + { + context.BranchIf(lblEnd, add, op, Comparison.GreaterOrEqualUI); + Operand right = context.BitwiseOr(shr, context.ShiftRightUI(oneShl63UL, context.Subtract(shift, one))); + context.Copy(res, context.ConditionalSelect(isEqual, oneUL, right)); + } + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + else + { + Operand lblEnd = Label(); + + Operand eSizeOp = Const(eSize); + Operand zeroUL = Const(0UL); + + Operand shr = context.ShiftRightUI(op, shift); + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), shr); + + context.BranchIf(lblEnd, shift, eSizeOp, Comparison.Less); + context.Copy(res, zeroUL); + context.Branch(lblEnd); + + context.MarkLabel(lblEnd); + + return res; + } + } } } diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs index e0968b7b1..9ac680884 100644 --- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs +++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs @@ -1,5 +1,6 @@ using ARMeilleure.Decoders; using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; using ARMeilleure.Translation; using System; using System.Diagnostics; @@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt)); - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); + SetFpFlag(context, FPState.QcFlag, Const(1)); context.MarkLabel(lblNoSat); diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs index cdfaa26ec..cc32228c3 100644 --- a/ARMeilleure/Instructions/InstEmitSystem.cs +++ b/ARMeilleure/Instructions/InstEmitSystem.cs @@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break; case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break; case 0b11_011_0100_0010_000: EmitGetNzcv(context); return; - case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break; - case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break; + case 0b11_011_0100_0100_000: EmitGetFpcr(context); return; + case 0b11_011_0100_0100_001: EmitGetFpsr(context); return; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break; case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break; case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break; @@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions switch (GetPackedId(op)) { - case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; - case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break; - case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break; + case 0b11_011_0100_0010_000: EmitSetNzcv(context); return; + case 0b11_011_0100_0100_000: EmitSetFpcr(context); return; + case 0b11_011_0100_0100_001: EmitSetFpsr(context); return; case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break; default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); @@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions { OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); - Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); - Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); - Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); + Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); + nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); - Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); + SetIntOrZR(context, op.Rt, nzcv); + } - SetIntOrZR(context, op.Rt, nzcvSh); + private static void EmitGetFpcr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpcr = Const(0); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) + { + fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } + + SetIntOrZR(context, op.Rt, fpcr); + } + + private static void EmitGetFpsr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpsr = Const(0); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) + { + fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } + + SetIntOrZR(context, op.Rt, fpsr); } private static void EmitSetNzcv(ArmEmitterContext context) { OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand t = GetIntOrZR(context, op.Rt); - t = context.ConvertI64ToI32(t); + Operand nzcv = GetIntOrZR(context, op.Rt); + nzcv = context.ConvertI64ToI32(nzcv); - Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag)); - v = context.BitwiseAnd (v, Const(1)); + SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1))); + SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1))); + SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1))); + SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1))); + } - Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag)); - c = context.BitwiseAnd (c, Const(1)); + private static void EmitSetFpcr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; - Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag)); - z = context.BitwiseAnd (z, Const(1)); + Operand fpcr = GetIntOrZR(context, op.Rt); + fpcr = context.ConvertI64ToI32(fpcr); - Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag)); - n = context.BitwiseAnd (n, Const(1)); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPCR.Mask.HasFlag((FPCR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1))); + } + } + } - SetFlag(context, PState.VFlag, v); - SetFlag(context, PState.CFlag, c); - SetFlag(context, PState.ZFlag, z); - SetFlag(context, PState.NFlag, n); + private static void EmitSetFpsr(ArmEmitterContext context) + { + OpCodeSystem op = (OpCodeSystem)context.CurrOp; + + Operand fpsr = GetIntOrZR(context, op.Rt); + fpsr = context.ConvertI64ToI32(fpsr); + + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSR.Mask.HasFlag((FPSR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1))); + } + } } } } diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs index acd17045f..e07db4121 100644 --- a/ARMeilleure/Instructions/InstEmitSystem32.cs +++ b/ARMeilleure/Instructions/InstEmitSystem32.cs @@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions } else { - Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); - Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)); - Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)); - Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)); - Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)); - - Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); - spsr = context.BitwiseOr(spsr, qSh); + Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); + spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag))); // TODO: Remaining flags. @@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions EmitSetNzcv(context, value); - Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag)); - q = context.BitwiseAnd(q, Const(1)); + Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1)); SetFlag(context, PState.QFlag, q); } @@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions private static void EmitSetNzcv(ArmEmitterContext context, Operand t) { - Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag)); - v = context.BitwiseAnd(v, Const(1)); - - Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag)); - c = context.BitwiseAnd(c, Const(1)); - - Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag)); - z = context.BitwiseAnd(z, Const(1)); - - Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag)); - n = context.BitwiseAnd(n, Const(1)); + Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1)); + Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1)); + Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1)); + Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1)); SetFlag(context, PState.VFlag, v); SetFlag(context, PState.CFlag, c); @@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions { OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; - Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag)); - Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag)); - Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag)); - Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag)); + Operand fpscr = Const(0); - Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh)); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) + { + fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); + } + } - Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); - - SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr)); + SetIntA32(context, op.Rt, fpscr); } private static void EmitSetFpscr(ArmEmitterContext context) { OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; - Operand t = GetIntA32(context, op.Rt); + Operand fpscr = GetIntA32(context, op.Rt); - Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag)); - v = context.BitwiseAnd(v, Const(1)); - - Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag)); - c = context.BitwiseAnd(c, Const(1)); - - Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag)); - z = context.BitwiseAnd(z, Const(1)); - - Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag)); - n = context.BitwiseAnd(n, Const(1)); - - SetFpFlag(context, FPState.VFlag, v); - SetFpFlag(context, FPState.CFlag, c); - SetFpFlag(context, FPState.ZFlag, z); - SetFpFlag(context, FPState.NFlag, n); - - context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t); + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) + { + SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1))); + } + } } } } diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs index ca4133ada..2ac748a9a 100644 --- a/ARMeilleure/Instructions/NativeInterface.cs +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions return (ulong)GetContext().DczidEl0; } - public static ulong GetFpcr() - { - return (ulong)GetContext().Fpcr; - } - - public static bool GetFpcrFz() - { - return (GetContext().Fpcr & FPCR.Fz) != 0; - } - - public static ulong GetFpsr() - { - return (ulong)GetContext().Fpsr; - } - - public static uint GetFpscr() - { - ExecutionContext context = GetContext(); - - return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) | - (uint)(context.Fpcr & FPCR.A32Mask); - } - public static ulong GetTpidrEl0() { return (ulong)GetContext().TpidrEl0; @@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions return GetContext().CntvctEl0; } - public static void SetFpcr(ulong value) - { - GetContext().Fpcr = (FPCR)value; - } - - public static void SetFpsr(ulong value) - { - GetContext().Fpsr = (FPSR)value; - } - - public static void SetFpsrQc() - { - GetContext().Fpsr |= FPSR.Qc; - } - - public static void SetFpscr(uint fpscr) - { - ExecutionContext context = GetContext(); - - context.Fpsr = FPSR.A32Mask & (FPSR)fpscr; - context.Fpcr = FPCR.A32Mask & (FPCR)fpscr; - } - public static void SetTpidrEl0(ulong value) { GetContext().TpidrEl0 = (long)value; diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs index 829dd37a3..06d76a67c 100644 --- a/ARMeilleure/Instructions/SoftFallback.cs +++ b/ARMeilleure/Instructions/SoftFallback.cs @@ -5,287 +5,6 @@ namespace ARMeilleure.Instructions { static class SoftFallback { -#region "ShlReg" - public static long SignedShlReg(long value, long shift, bool round, int size) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return SignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return 0L; - } - - return value << shiftLsB; - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static ulong UnsignedShlReg(ulong value, ulong shift, bool round, int size) - { - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return UnsignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return 0UL; - } - - return value << shiftLsB; - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static long SignedShlRegSatQ(long value, long shift, bool round, int size) - { - ExecutionContext context = NativeInterface.GetContext(); - - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return SignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return SignedSignSatQ(value, eSize, context); - } - - if (eSize == 64) - { - long shl = value << shiftLsB; - long shr = shl >> shiftLsB; - - if (shr != value) - { - return SignedSignSatQ(value, eSize, context); - } - else /* if (shr == value) */ - { - return shl; - } - } - else /* if (eSize != 64) */ - { - return SignedSrcSignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitSignedSrcSatQ(signedDst: true). - } - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - public static ulong UnsignedShlRegSatQ(ulong value, ulong shift, bool round, int size) - { - ExecutionContext context = NativeInterface.GetContext(); - - int eSize = 8 << size; - - int shiftLsB = (sbyte)shift; - - if (shiftLsB < 0) - { - return UnsignedShrReg(value, -shiftLsB, round, eSize); - } - else if (shiftLsB > 0) - { - if (shiftLsB >= eSize) - { - return UnsignedSignSatQ(value, eSize, context); - } - - if (eSize == 64) - { - ulong shl = value << shiftLsB; - ulong shr = shl >> shiftLsB; - - if (shr != value) - { - return UnsignedSignSatQ(value, eSize, context); - } - else /* if (shr == value) */ - { - return shl; - } - } - else /* if (eSize != 64) */ - { - return UnsignedSrcUnsignedDstSatQ(value << shiftLsB, size); // InstEmitSimdHelper.EmitUnsignedSrcSatQ(signedDst: false). - } - } - else /* if (shiftLsB == 0) */ - { - return value; - } - } - - private static long SignedShrReg(long value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}. - { - if (round) - { - if (shift >= eSize) - { - return 0L; - } - - long roundConst = 1L << (shift - 1); - - long add = value + roundConst; - - if (eSize == 64) - { - if ((~value & (value ^ add)) < 0L) - { - return (long)((ulong)add >> shift); - } - else - { - return add >> shift; - } - } - else /* if (eSize != 64) */ - { - return add >> shift; - } - } - else /* if (!round) */ - { - if (shift >= eSize) - { - if (value < 0L) - { - return -1L; - } - else /* if (value >= 0L) */ - { - return 0L; - } - } - - return value >> shift; - } - } - - private static ulong UnsignedShrReg(ulong value, int shift, bool round, int eSize) // shift := [1, 128]; eSize := {8, 16, 32, 64}. - { - if (round) - { - if (shift > 64) - { - return 0UL; - } - - ulong roundConst = 1UL << (shift - 1); - - ulong add = value + roundConst; - - if (eSize == 64) - { - if ((add < value) && (add < roundConst)) - { - if (shift == 64) - { - return 1UL; - } - - return (add >> shift) | (0x8000000000000000UL >> (shift - 1)); - } - else - { - if (shift == 64) - { - return 0UL; - } - - return add >> shift; - } - } - else /* if (eSize != 64) */ - { - if (shift == 64) - { - return 0UL; - } - - return add >> shift; - } - } - else /* if (!round) */ - { - if (shift >= eSize) - { - return 0UL; - } - - return value >> shift; - } - } - - private static long SignedSignSatQ(long op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}. - { - long tMaxValue = (1L << (eSize - 1)) - 1L; - long tMinValue = -(1L << (eSize - 1)); - - if (op > 0L) - { - context.Fpsr |= FPSR.Qc; - - return tMaxValue; - } - else if (op < 0L) - { - context.Fpsr |= FPSR.Qc; - - return tMinValue; - } - else - { - return 0L; - } - } - - private static ulong UnsignedSignSatQ(ulong op, int eSize, ExecutionContext context) // eSize := {8, 16, 32, 64}. - { - ulong tMaxValue = ulong.MaxValue >> (64 - eSize); - - if (op > 0UL) - { - context.Fpsr |= FPSR.Qc; - - return tMaxValue; - } - else - { - return 0UL; - } - } -#endregion - #region "ShrImm64" public static long SignedShrImm64(long value, long roundConst, int shift) { @@ -372,76 +91,6 @@ namespace ARMeilleure.Instructions } #endregion -#region "Rounding" - public static double Round(double value) - { - ExecutionContext context = NativeInterface.GetContext(); - - FPRoundingMode roundMode = context.Fpcr.GetRoundingMode(); - - if (roundMode == FPRoundingMode.ToNearest) - { - return Math.Round(value); // even - } - else if (roundMode == FPRoundingMode.TowardsPlusInfinity) - { - return Math.Ceiling(value); - } - else if (roundMode == FPRoundingMode.TowardsMinusInfinity) - { - return Math.Floor(value); - } - else /* if (roundMode == FPRoundingMode.TowardsZero) */ - { - return Math.Truncate(value); - } - } - - public static float RoundF(float value) - { - ExecutionContext context = NativeInterface.GetContext(); - - FPRoundingMode roundMode = context.Fpcr.GetRoundingMode(); - - if (roundMode == FPRoundingMode.ToNearest) - { - return MathF.Round(value); // even - } - else if (roundMode == FPRoundingMode.TowardsPlusInfinity) - { - return MathF.Ceiling(value); - } - else if (roundMode == FPRoundingMode.TowardsMinusInfinity) - { - return MathF.Floor(value); - } - else /* if (roundMode == FPRoundingMode.TowardsZero) */ - { - return MathF.Truncate(value); - } - } - - public static int FloatToInt32(float value) - { - return SatF32ToS32(RoundF(value)); - } - - public static int DoubleToInt32(double value) - { - return SatF64ToS32(Round(value)); - } - - public static uint FloatToUInt32(float value) - { - return SatF32ToU32(RoundF(value)); - } - - public static uint DoubleToUInt32(double value) - { - return SatF64ToU32(Round(value)); - } -#endregion - #region "Saturation" public static int SatF32ToS32(float value) { @@ -508,55 +157,6 @@ namespace ARMeilleure.Instructions } #endregion -#region "Saturating" - private static long SignedSrcSignedDstSatQ(long op, int size) - { - ExecutionContext context = NativeInterface.GetContext(); - - int eSize = 8 << size; - - long tMaxValue = (1L << (eSize - 1)) - 1L; - long tMinValue = -(1L << (eSize - 1)); - - if (op > tMaxValue) - { - context.Fpsr |= FPSR.Qc; - - return tMaxValue; - } - else if (op < tMinValue) - { - context.Fpsr |= FPSR.Qc; - - return tMinValue; - } - else - { - return op; - } - } - - private static ulong UnsignedSrcUnsignedDstSatQ(ulong op, int size) - { - ExecutionContext context = NativeInterface.GetContext(); - - int eSize = 8 << size; - - ulong tMaxValue = (1UL << eSize) - 1UL; - - if (op > tMaxValue) - { - context.Fpsr |= FPSR.Qc; - - return tMaxValue; - } - else - { - return op; - } - } -#endregion - #region "Count" public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.). { diff --git a/ARMeilleure/Instructions/SoftFloat.cs b/ARMeilleure/Instructions/SoftFloat.cs index a138f5df2..9e3db68d9 100644 --- a/ARMeilleure/Instructions/SoftFloat.cs +++ b/ARMeilleure/Instructions/SoftFloat.cs @@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable(); } - internal static readonly byte[] RecipEstimateTable; - internal static readonly byte[] RecipSqrtEstimateTable; + public static readonly byte[] RecipEstimateTable; + public static readonly byte[] RecipSqrtEstimateTable; private static byte[] BuildRecipEstimateTable() { @@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions context.Fpsr |= (FPSR)(1 << (int)exc); } } + + public static FPRoundingMode GetRoundingMode(this FPCR fpcr) + { + const int RModeShift = 22; + + return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u); + } } static class SoftFloat16 diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index c73ca197d..5d18e6ed8 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -36,10 +36,25 @@ namespace ARMeilleure.State set => _nativeContext.SetPstate(value); } - public FPCR Fpcr { get; set; } - public FPSR Fpsr { get; set; } + public FPSR Fpsr + { + get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask); + } + + public FPCR Fpcr + { + get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask); + } public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz; + public FPSCR Fpscr + { + get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask); + set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask); + } + public bool IsAarch32 { get; set; } internal ExecutionMode ExecutionMode diff --git a/ARMeilleure/State/FPCR.cs b/ARMeilleure/State/FPCR.cs index 40d560455..6f707de7d 100644 --- a/ARMeilleure/State/FPCR.cs +++ b/ARMeilleure/State/FPCR.cs @@ -5,21 +5,18 @@ namespace ARMeilleure.State [Flags] public enum FPCR : uint { + Ioe = 1u << 8, + Dze = 1u << 9, + Ofe = 1u << 10, Ufe = 1u << 11, + Ixe = 1u << 12, + Ide = 1u << 15, + RMode0 = 1u << 22, + RMode1 = 1u << 23, Fz = 1u << 24, Dn = 1u << 25, Ahp = 1u << 26, - A32Mask = 0x07FF9F00u - } - - public static class FPCRExtensions - { - private const int RModeShift = 22; - - public static FPRoundingMode GetRoundingMode(this FPCR fpcr) - { - return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3); - } + Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u } } diff --git a/ARMeilleure/State/FPSCR.cs b/ARMeilleure/State/FPSCR.cs new file mode 100644 index 000000000..d6d2fc26a --- /dev/null +++ b/ARMeilleure/State/FPSCR.cs @@ -0,0 +1,15 @@ +using System; + +namespace ARMeilleure.State +{ + [Flags] + public enum FPSCR : uint + { + V = 1u << 28, + C = 1u << 29, + Z = 1u << 30, + N = 1u << 31, + + Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu + } +} diff --git a/ARMeilleure/State/FPSR.cs b/ARMeilleure/State/FPSR.cs index 800dcd10c..5e66d5ce1 100644 --- a/ARMeilleure/State/FPSR.cs +++ b/ARMeilleure/State/FPSR.cs @@ -5,11 +5,14 @@ namespace ARMeilleure.State [Flags] public enum FPSR : uint { + Ioc = 1u << 0, + Dzc = 1u << 1, + Ofc = 1u << 2, Ufc = 1u << 3, - Qc = 1u << 27, + Ixc = 1u << 4, + Idc = 1u << 7, + Qc = 1u << 27, - Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28), - - A32Mask = 0xF800009Fu + Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu } } diff --git a/ARMeilleure/State/FPState.cs b/ARMeilleure/State/FPState.cs index 60c7126c3..fa6ab9d46 100644 --- a/ARMeilleure/State/FPState.cs +++ b/ARMeilleure/State/FPState.cs @@ -2,9 +2,30 @@ { public enum FPState { + // FPSR Flags. + IocFlag = 0, + DzcFlag = 1, + OfcFlag = 2, + UfcFlag = 3, + IxcFlag = 4, + IdcFlag = 7, + QcFlag = 27, VFlag = 28, CFlag = 29, ZFlag = 30, - NFlag = 31 + NFlag = 31, + + // FPCR Flags. + IoeFlag = 8, + DzeFlag = 9, + OfeFlag = 10, + UfeFlag = 11, + IxeFlag = 12, + IdeFlag = 15, + RMode0Flag = 22, + RMode1Flag = 23, + FzFlag = 24, + DnFlag = 25, + AhpFlag = 26 } } diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs index 11ab5ca3a..89e875d12 100644 --- a/ARMeilleure/State/NativeContext.cs +++ b/ARMeilleure/State/NativeContext.cs @@ -140,6 +140,34 @@ namespace ARMeilleure.State GetStorage().FpFlags[(int)flag] = value ? 1u : 0u; } + public unsafe uint GetFPState(uint mask = uint.MaxValue) + { + uint value = 0; + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + uint bit = 1u << flag; + + if ((mask & bit) == bit) + { + value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u; + } + } + return value; + } + + public unsafe void SetFPState(uint value, uint mask = uint.MaxValue) + { + for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) + { + uint bit = 1u << flag; + + if ((mask & bit) == bit) + { + GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u; + } + } + } + public int GetCounter() => GetStorage().Counter; public void SetCounter(int value) => GetStorage().Counter = value; diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs index b36472b83..fef1f4ef7 100644 --- a/ARMeilleure/Translation/Delegates.cs +++ b/ARMeilleure/Translation/Delegates.cs @@ -109,10 +109,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0))); @@ -124,10 +120,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only. - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr))); - SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only. SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking))); @@ -151,12 +143,8 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only. - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only. SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only. - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only. SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority))); @@ -165,8 +153,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))); @@ -179,8 +165,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2))); @@ -190,8 +174,6 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg))); - SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ))); SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64))); SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert))); diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 71f69ef7c..f4ae411b7 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 3695; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1"; diff --git a/README.md b/README.md index 83f56f66a..9a8581e06 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@

- +

diff --git a/Ryujinx.Ava/AppHost.cs b/Ryujinx.Ava/AppHost.cs index 7e3cddc88..320efeb5e 100644 --- a/Ryujinx.Ava/AppHost.cs +++ b/Ryujinx.Ava/AppHost.cs @@ -1,6 +1,5 @@ using ARMeilleure.Translation; using ARMeilleure.Translation.PTC; -using Avalonia; using Avalonia.Input; using Avalonia.Threading; using LibHac.Tools.FsSystem; @@ -12,10 +11,8 @@ using Ryujinx.Audio.Integration; using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; -using Ryujinx.Ava.Ui.Backend.Vulkan; using Ryujinx.Ava.Ui.Controls; using Ryujinx.Ava.Ui.Models; -using Ryujinx.Ava.Ui.Vulkan; using Ryujinx.Ava.Ui.Windows; using Ryujinx.Common; using Ryujinx.Common.Configuration; @@ -39,6 +36,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SPB.Graphics.Vulkan; using System; using System.Diagnostics; using System.IO; @@ -58,24 +56,24 @@ namespace Ryujinx.Ava { private const int CursorHideIdleTime = 8; // Hide Cursor seconds private const float MaxResolutionScale = 4.0f; // Max resolution hotkeys can scale to before wrapping. + private const int TargetFps = 60; - private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None); + private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None); + private readonly long _ticksPerFrame; + private readonly Stopwatch _chrono; private readonly AccountManager _accountManager; private readonly UserChannelPersistence _userChannelPersistence; - private readonly InputManager _inputManager; - - private readonly IKeyboard _keyboardInterface; - private readonly MainWindow _parent; - + private readonly IKeyboard _keyboardInterface; private readonly GraphicsDebugLevel _glLogLevel; private bool _hideCursorOnIdle; private bool _isStopped; private bool _isActive; private long _lastCursorMoveTime; + private long _ticks = 0; private KeyboardHotkeyState _prevHotkeyState; @@ -93,7 +91,7 @@ namespace Ryujinx.Ava public event EventHandler AppExit; public event EventHandler StatusUpdatedEvent; - public RendererControl Renderer { get; } + public RendererHost Renderer { get; } public VirtualFileSystem VirtualFileSystem { get; } public ContentManager ContentManager { get; } public Switch Device { get; set; } @@ -111,7 +109,7 @@ namespace Ryujinx.Ava private object _lockObject = new(); public AppHost( - RendererControl renderer, + RendererHost renderer, InputManager inputManager, string applicationPath, VirtualFileSystem virtualFileSystem, @@ -128,7 +126,7 @@ namespace Ryujinx.Ava _hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle; _lastCursorMoveTime = Stopwatch.GetTimestamp(); _glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel; - _inputManager.SetMouseDriver(new AvaloniaMouseDriver(renderer)); + _inputManager.SetMouseDriver(new AvaloniaMouseDriver(_parent, renderer)); _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0"); NpadManager = _inputManager.CreateNpadManager(); @@ -138,6 +136,9 @@ namespace Ryujinx.Ava VirtualFileSystem = virtualFileSystem; ContentManager = contentManager; + _chrono = new Stopwatch(); + _ticksPerFrame = Stopwatch.Frequency / TargetFps; + if (ApplicationPath.StartsWith("@SystemContent")) { ApplicationPath = _parent.VirtualFileSystem.SwitchPathToSystemPath(ApplicationPath); @@ -177,7 +178,7 @@ namespace Ryujinx.Ava if (_renderer != null) { double scale = _parent.PlatformImpl.RenderScaling; - _renderer.Window.SetSize((int)(size.Width * scale), (int)(size.Height * scale)); + _renderer.Window?.SetSize((int)(size.Width * scale), (int)(size.Height * scale)); } } @@ -335,8 +336,6 @@ namespace Ryujinx.Ava return; } - AvaloniaLocator.Current.GetService()?.MainSurface.Display.ChangeVSyncMode(true); - _isStopped = true; _isActive = false; } @@ -376,6 +375,8 @@ namespace Ryujinx.Ava _gpuCancellationTokenSource.Cancel(); _gpuCancellationTokenSource.Dispose(); + + _chrono.Stop(); } public void DisposeGpu() @@ -389,8 +390,7 @@ namespace Ryujinx.Ava Renderer?.MakeCurrent(); Device.DisposeGpu(); - - Renderer?.DestroyBackgroundContext(); + Renderer?.MakeCurrent(null); } @@ -596,16 +596,11 @@ namespace Ryujinx.Ava IRenderer renderer; - if (Program.UseVulkan) + if (Renderer.IsVulkan) { - var vulkan = AvaloniaLocator.Current.GetService(); + string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value; - renderer = new VulkanRenderer(vulkan.Instance.InternalHandle, - vulkan.MainSurface.Device.InternalHandle, - vulkan.PhysicalDevice.InternalHandle, - vulkan.MainSurface.Device.Queue.InternalHandle, - vulkan.PhysicalDevice.QueueFamilyIndex, - vulkan.MainSurface.Device.Lock); + renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu); } else { @@ -778,11 +773,7 @@ namespace Ryujinx.Ava { Width = (int)e.Width; Height = (int)e.Height; - - if (!Program.UseVulkan) - { - SetRendererWindowSize(e); - } + SetRendererWindowSize(e); } private void MainLoop() @@ -822,12 +813,10 @@ namespace Ryujinx.Ava _renderer.ScreenCaptured += Renderer_ScreenCaptured; - (_renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext((Renderer as OpenGLRendererControl).GameContext)); + (_renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(Renderer.GetContext())); Renderer.MakeCurrent(); - AvaloniaLocator.Current.GetService()?.MainSurface?.Display?.ChangeVSyncMode(Device.EnableDeviceVsync); - Device.Gpu.Renderer.Initialize(_glLogLevel); Width = (int)Renderer.Bounds.Width; @@ -835,16 +824,20 @@ namespace Ryujinx.Ava _renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling)); + _chrono.Start(); + Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); Translator.IsReadyForTranslation.Set(); - Renderer.Start(); - while (_isActive) { + _ticks += _chrono.ElapsedTicks; + + _chrono.Restart(); + if (Device.WaitFifo()) { Device.Statistics.RecordFifoStart(); @@ -860,19 +853,20 @@ namespace Ryujinx.Ava _parent.SwitchToGameControl(); } - Device.PresentFrame(Present); + Device.PresentFrame(() => Renderer?.SwapBuffers()); + } + + if (_ticks >= _ticksPerFrame) + { + UpdateStatus(); } } - - Renderer.Stop(); }); Renderer?.MakeCurrent(null); - - Renderer.SizeChanged -= Window_SizeChanged; } - private void Present(object image) + public void UpdateStatus() { // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"]; @@ -885,25 +879,13 @@ namespace Ryujinx.Ava StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs( Device.EnableDeviceVsync, - Device.GetVolume(), - Program.UseVulkan ? "Vulkan" : "OpenGL", + LocaleManager.Instance["VolumeShort"] + $": {(int)(Device.GetVolume() * 100)}%", + Renderer.IsVulkan ? "Vulkan" : "OpenGL", dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", $"GPU: {_renderer.GetHardwareInfo().GpuVendor}")); - - if (Program.UseVulkan) - { - var platformInterface = AvaloniaLocator.Current.GetService(); - if (platformInterface.MainSurface.Display.IsSurfaceChanged()) - { - SetRendererWindowSize(new Size(Width, Height)); - return; - } - } - - Renderer.Present(image); } public async Task ShowExitPrompt() @@ -985,8 +967,6 @@ namespace Ryujinx.Ava case KeyboardHotkeyState.ToggleVSync: Device.EnableDeviceVsync = !Device.EnableDeviceVsync; - AvaloniaLocator.Current.GetService()?.MainSurface?.Display?.ChangeVSyncMode(Device.EnableDeviceVsync); - break; case KeyboardHotkeyState.Screenshot: ScreenshotRequested = true; diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json index 350e20635..a6641a028 100644 --- a/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/Ryujinx.Ava/Assets/Locales/en_US.json @@ -588,5 +588,6 @@ "SettingsTabGraphicsPreferredGpuTooltip": "Select the graphics card that will be used with the Vulkan graphics backend.\n\nDoes not affect the GPU that OpenGL will use.\n\nSet to the GPU flagged as \"dGPU\" if unsure. If there isn't one, leave untouched.", "SettingsAppRequiredRestartMessage": "Ryujinx Restart Required", "SettingsGpuBackendRestartMessage": "Graphics Backend or Gpu settings have been modified. This will require a restart to be applied", - "SettingsGpuBackendRestartSubMessage": "Do you want to restart now?" + "SettingsGpuBackendRestartSubMessage": "Do you want to restart now?", + "VolumeShort": "Vol" } diff --git a/Ryujinx.Ava/Assets/Styles/Styles.xaml b/Ryujinx.Ava/Assets/Styles/Styles.xaml index c93640ae9..8b09bafdd 100644 --- a/Ryujinx.Ava/Assets/Styles/Styles.xaml +++ b/Ryujinx.Ava/Assets/Styles/Styles.xaml @@ -54,6 +54,12 @@ + @@ -193,6 +199,14 @@ + + + + + + + + diff --git a/Ryujinx.Ava/Ui/Windows/ContentDialogOverlayWindow.axaml.cs b/Ryujinx.Ava/Ui/Windows/ContentDialogOverlayWindow.axaml.cs new file mode 100644 index 000000000..7a51e64d0 --- /dev/null +++ b/Ryujinx.Ava/Ui/Windows/ContentDialogOverlayWindow.axaml.cs @@ -0,0 +1,25 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Media; + +namespace Ryujinx.Ava.Ui.Windows +{ + public partial class ContentDialogOverlayWindow : StyleableWindow + { + public ContentDialogOverlayWindow() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + ExtendClientAreaToDecorationsHint = true; + TransparencyLevelHint = WindowTransparencyLevel.Transparent; + WindowStartupLocation = WindowStartupLocation.Manual; + SystemDecorations = SystemDecorations.None; + ExtendClientAreaTitleBarHeightHint = 0; + Background = Brushes.Transparent; + CanResize = false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml b/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml index f34dd212e..7ddf67197 100644 --- a/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml +++ b/Ryujinx.Ava/Ui/Windows/ControllerSettingsWindow.axaml @@ -35,7 +35,8 @@ Grid.Column="0" Margin="0,0,2,0" BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1"> + BorderThickness="1" + Padding="2,0"> + BorderThickness="1" + Padding="2,0"> + BorderThickness="1" + Padding="2,0"> + BorderThickness="1" + Padding="2,0" >