diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index ae4be5a659..c8c8711989 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -36,8 +36,8 @@ namespace ARMeilleure.CodeGen.X86 Add(Instruction.CompareLessUI, GenerateCompareLessUI); Add(Instruction.CompareNotEqual, GenerateCompareNotEqual); Add(Instruction.ConditionalSelect, GenerateConditionalSelect); - Add(Instruction.CountLeadingZeros, GenerateCountLeadingZeros); Add(Instruction.Copy, GenerateCopy); + Add(Instruction.CountLeadingZeros, GenerateCountLeadingZeros); Add(Instruction.Divide, GenerateDivide); Add(Instruction.Fill, GenerateFill); Add(Instruction.Load, GenerateLoad); @@ -229,34 +229,6 @@ namespace ARMeilleure.CodeGen.X86 context.Assembler.Cmovcc(operation.Dest, operation.GetSource(1), X86Condition.NotEqual); } - private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation) - { - Operand dest = operation.Dest; - - Operand dest32 = Get32BitsRegister(dest.GetRegister()); - - context.Assembler.Bsr(dest, operation.GetSource(0)); - - int operandSize = dest.Type == OperandType.I32 ? 32 : 64; - int operandMask = operandSize - 1; - - //When the input operand is 0, the result is undefined, however the - //ZF flag is set. We are supposed to return the operand size on that - //case. So, add an additional jump to handle that case, by moving the - //operand size constant to the destination register. - context.JumpToNear(X86Condition.NotEqual); - - context.Assembler.Mov(dest32, new Operand(operandSize | operandMask)); - - context.JumpHere(); - - //BSR returns the zero based index of the last bit set on the operand, - //starting from the least significant bit. However we are supposed to - //return the number of 0 bits on the high end. So, we invert the result - //of the BSR using XOR to get the correct value. - context.Assembler.Xor(dest32, new Operand(operandMask)); - } - private static void GenerateCopy(CodeGenContext context, Operation operation) { Operand dest = operation.Dest; @@ -299,6 +271,34 @@ namespace ARMeilleure.CodeGen.X86 } } + private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation) + { + Operand dest = operation.Dest; + + Operand dest32 = Get32BitsRegister(dest.GetRegister()); + + context.Assembler.Bsr(dest, operation.GetSource(0)); + + int operandSize = dest.Type == OperandType.I32 ? 32 : 64; + int operandMask = operandSize - 1; + + //When the input operand is 0, the result is undefined, however the + //ZF flag is set. We are supposed to return the operand size on that + //case. So, add an additional jump to handle that case, by moving the + //operand size constant to the destination register. + context.JumpToNear(X86Condition.NotEqual); + + context.Assembler.Mov(dest32, new Operand(operandSize | operandMask)); + + context.JumpHere(); + + //BSR returns the zero based index of the last bit set on the operand, + //starting from the least significant bit. However we are supposed to + //return the number of 0 bits on the high end. So, we invert the result + //of the BSR using XOR to get the correct value. + context.Assembler.Xor(dest32, new Operand(operandMask)); + } + private static void GenerateDivide(CodeGenContext context, Operation operation) { Operand divisor = operation.GetSource(1); diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs index e7039d65d6..2e8c763cd3 100644 --- a/ARMeilleure/Common/BitUtils.cs +++ b/ARMeilleure/Common/BitUtils.cs @@ -4,19 +4,19 @@ namespace ARMeilleure.Common { static class BitUtils { - private const int deBrujinSequence = 0x77cb531; + private const int DeBrujinSequence = 0x77cb531; - private static int[] deBrujinLbsLut; + private static int[] DeBrujinLbsLut; static BitUtils() { - deBrujinLbsLut = new int[32]; + DeBrujinLbsLut = new int[32]; - for (int index = 0; index < deBrujinLbsLut.Length; index++) + for (int index = 0; index < DeBrujinLbsLut.Length; index++) { - uint lutIndex = (uint)(deBrujinSequence * (1 << index)) >> 27; + uint lutIndex = (uint)(DeBrujinSequence * (1 << index)) >> 27; - deBrujinLbsLut[lutIndex] = index; + DeBrujinLbsLut[lutIndex] = index; } } @@ -30,7 +30,7 @@ namespace ARMeilleure.Common int lsb = value & -value; - return deBrujinLbsLut[(uint)(deBrujinSequence * lsb) >> 27]; + return DeBrujinLbsLut[(uint)(DeBrujinSequence * lsb) >> 27]; } public static int HighestBitSet(int value) diff --git a/ARMeilleure/State/V128.cs b/ARMeilleure/State/V128.cs index c96bf999fd..8706b0f590 100644 --- a/ARMeilleure/State/V128.cs +++ b/ARMeilleure/State/V128.cs @@ -2,7 +2,7 @@ using System; namespace ARMeilleure.State { - public struct V128 + public struct V128 : IEquatable { private ulong _e0; private ulong _e1; @@ -71,5 +71,30 @@ namespace ARMeilleure.State throw new ArgumentOutOfRangeException(nameof(index)); } + + public override int GetHashCode() + { + return HashCode.Combine(_e0, _e1); + } + + public static bool operator ==(V128 x, V128 y) + { + return x.Equals(y); + } + + public static bool operator !=(V128 x, V128 y) + { + return !x.Equals(y); + } + + public override bool Equals(object obj) + { + return obj is V128 vector && Equals(vector); + } + + public bool Equals(V128 other) + { + return other._e0 == _e0 && other._e1 == _e1; + } } } \ No newline at end of file diff --git a/Ryujinx.Tests.Unicorn/SimdValue.cs b/Ryujinx.Tests.Unicorn/SimdValue.cs index 47e092d5c6..2d96741988 100644 --- a/Ryujinx.Tests.Unicorn/SimdValue.cs +++ b/Ryujinx.Tests.Unicorn/SimdValue.cs @@ -2,7 +2,7 @@ using System; namespace Ryujinx.Tests.Unicorn { - public struct SimdValue + public struct SimdValue : IEquatable { private ulong _e0; private ulong _e1; @@ -76,5 +76,30 @@ namespace Ryujinx.Tests.Unicorn throw new ArgumentOutOfRangeException(nameof(index)); } + + public override int GetHashCode() + { + return HashCode.Combine(_e0, _e1); + } + + public static bool operator ==(SimdValue x, SimdValue y) + { + return x.Equals(y); + } + + public static bool operator !=(SimdValue x, SimdValue y) + { + return !x.Equals(y); + } + + public override bool Equals(object obj) + { + return obj is SimdValue simdValue && Equals(simdValue); + } + + public bool Equals(SimdValue other) + { + return other._e0 == _e0 && other._e1 == _e1; + } } } \ No newline at end of file