diff options
Diffstat (limited to 'ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs')
-rw-r--r-- | ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs b/ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs new file mode 100644 index 00000000..e67d2fdb --- /dev/null +++ b/ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs @@ -0,0 +1,173 @@ +using ARMeilleure.IntermediateRepresentation; +using System; +using System.Numerics; + +namespace ARMeilleure.CodeGen.Arm64 +{ + static class CodeGenCommon + { + public const int TcAddressRegister = 8; + public const int ReservedRegister = 17; + + public static bool ConstFitsOnSImm7(int value, int scale) + { + return (((value >> scale) << 25) >> (25 - scale)) == value; + } + + public static bool ConstFitsOnSImm9(int value) + { + return ((value << 23) >> 23) == value; + } + + public static bool ConstFitsOnUImm12(int value) + { + return (value & 0xfff) == value; + } + + public static bool ConstFitsOnUImm12(int value, OperandType type) + { + int scale = Assembler.GetScaleForType(type); + return (((value >> scale) & 0xfff) << scale) == value; + } + + public static bool TryEncodeBitMask(Operand operand, out int immN, out int immS, out int immR) + { + ulong value = operand.Value; + + if (operand.Type == OperandType.I32) + { + value |= value << 32; + } + + return TryEncodeBitMask(value, out immN, out immS, out immR); + } + + public static bool TryEncodeBitMask(ulong value, out int immN, out int immS, out int immR) + { + // Some special values also can't be encoded: + // 0 can't be encoded because we need to subtract 1 from onesCount (which would became negative if 0). + // A value with all bits set can't be encoded because it is reserved according to the spec, because: + // Any value AND all ones will be equal itself, so it's effectively a no-op. + // Any value OR all ones will be equal all ones, so one can just use MOV. + // Any value XOR all ones will be equal its inverse, so one can just use MVN. + if (value == ulong.MaxValue) + { + immN = 0; + immS = 0; + immR = 0; + + return false; + } + + int bitLength = CountSequence(value); + + if ((value >> bitLength) != 0) + { + bitLength += CountSequence(value >> bitLength); + } + + int bitLengthLog2 = BitOperations.Log2((uint)bitLength); + int bitLengthPow2 = 1 << bitLengthLog2; + + if (bitLengthPow2 < bitLength) + { + bitLengthLog2++; + bitLengthPow2 <<= 1; + } + + int selectedESize = 64; + int repetitions = 1; + int onesCount = BitOperations.PopCount(value); + + if (bitLengthPow2 < 64 && (value >> bitLengthPow2) != 0) + { + for (int eSizeLog2 = bitLengthLog2; eSizeLog2 < 6; eSizeLog2++) + { + bool match = true; + int eSize = 1 << eSizeLog2; + ulong mask = (1UL << eSize) - 1; + ulong eValue = value & mask; + + for (int e = 1; e < 64 / eSize; e++) + { + if (((value >> (e * eSize)) & mask) != eValue) + { + match = false; + break; + } + } + + if (match) + { + selectedESize = eSize; + repetitions = 64 / eSize; + onesCount = BitOperations.PopCount(eValue); + break; + } + } + } + + // Find rotation. We have two cases, one where the highest bit is 0 + // and one where it is 1. + // If it's 1, we just need to count the number of 1 bits on the MSB to find the right rotation. + // If it's 0, we just need to count the number of 0 bits on the LSB to find the left rotation, + // then we can convert it to the right rotation shift by subtracting the value from the element size. + int rotation; + long vHigh = (long)(value << (64 - selectedESize)); + if (vHigh < 0) + { + rotation = BitOperations.LeadingZeroCount(~(ulong)vHigh); + } + else + { + rotation = (selectedESize - BitOperations.TrailingZeroCount(value)) & (selectedESize - 1); + } + + // Reconstruct value and see if it matches. If not, we can't encode. + ulong reconstructed = onesCount == 64 ? ulong.MaxValue : RotateRight((1UL << onesCount) - 1, rotation, selectedESize); + + for (int bit = 32; bit >= selectedESize; bit >>= 1) + { + reconstructed |= reconstructed << bit; + } + + if (reconstructed != value || onesCount == 0) + { + immN = 0; + immS = 0; + immR = 0; + + return false; + } + + immR = rotation; + + // immN indicates that there are no repetitions. + // The MSB of immS indicates the amount of repetitions, and the LSB the number of bits set. + if (repetitions == 1) + { + immN = 1; + immS = 0; + } + else + { + immN = 0; + immS = (0xf80 >> BitOperations.Log2((uint)repetitions)) & 0x3f; + } + + immS |= onesCount - 1; + + return true; + } + + private static int CountSequence(ulong value) + { + return BitOperations.TrailingZeroCount(value) + BitOperations.TrailingZeroCount(~value); + } + + private static ulong RotateRight(ulong bits, int shift, int size) + { + return (bits >> shift) | ((bits << (size - shift)) & (size == 64 ? ulong.MaxValue : (1UL << size) - 1)); + } + } +}
\ No newline at end of file |