aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs')
-rw-r--r--ARMeilleure/CodeGen/Arm64/CodeGenCommon.cs173
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