| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- 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));
- }
- }
- }
|