CodeGenCommon.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using System.Numerics;
  4. namespace ARMeilleure.CodeGen.Arm64
  5. {
  6. static class CodeGenCommon
  7. {
  8. public const int TcAddressRegister = 8;
  9. public const int ReservedRegister = 17;
  10. public static bool ConstFitsOnSImm7(int value, int scale)
  11. {
  12. return (((value >> scale) << 25) >> (25 - scale)) == value;
  13. }
  14. public static bool ConstFitsOnSImm9(int value)
  15. {
  16. return ((value << 23) >> 23) == value;
  17. }
  18. public static bool ConstFitsOnUImm12(int value)
  19. {
  20. return (value & 0xfff) == value;
  21. }
  22. public static bool ConstFitsOnUImm12(int value, OperandType type)
  23. {
  24. int scale = Assembler.GetScaleForType(type);
  25. return (((value >> scale) & 0xfff) << scale) == value;
  26. }
  27. public static bool TryEncodeBitMask(Operand operand, out int immN, out int immS, out int immR)
  28. {
  29. ulong value = operand.Value;
  30. if (operand.Type == OperandType.I32)
  31. {
  32. value |= value << 32;
  33. }
  34. return TryEncodeBitMask(value, out immN, out immS, out immR);
  35. }
  36. public static bool TryEncodeBitMask(ulong value, out int immN, out int immS, out int immR)
  37. {
  38. // Some special values also can't be encoded:
  39. // 0 can't be encoded because we need to subtract 1 from onesCount (which would became negative if 0).
  40. // A value with all bits set can't be encoded because it is reserved according to the spec, because:
  41. // Any value AND all ones will be equal itself, so it's effectively a no-op.
  42. // Any value OR all ones will be equal all ones, so one can just use MOV.
  43. // Any value XOR all ones will be equal its inverse, so one can just use MVN.
  44. if (value == ulong.MaxValue)
  45. {
  46. immN = 0;
  47. immS = 0;
  48. immR = 0;
  49. return false;
  50. }
  51. int bitLength = CountSequence(value);
  52. if ((value >> bitLength) != 0)
  53. {
  54. bitLength += CountSequence(value >> bitLength);
  55. }
  56. int bitLengthLog2 = BitOperations.Log2((uint)bitLength);
  57. int bitLengthPow2 = 1 << bitLengthLog2;
  58. if (bitLengthPow2 < bitLength)
  59. {
  60. bitLengthLog2++;
  61. bitLengthPow2 <<= 1;
  62. }
  63. int selectedESize = 64;
  64. int repetitions = 1;
  65. int onesCount = BitOperations.PopCount(value);
  66. if (bitLengthPow2 < 64 && (value >> bitLengthPow2) != 0)
  67. {
  68. for (int eSizeLog2 = bitLengthLog2; eSizeLog2 < 6; eSizeLog2++)
  69. {
  70. bool match = true;
  71. int eSize = 1 << eSizeLog2;
  72. ulong mask = (1UL << eSize) - 1;
  73. ulong eValue = value & mask;
  74. for (int e = 1; e < 64 / eSize; e++)
  75. {
  76. if (((value >> (e * eSize)) & mask) != eValue)
  77. {
  78. match = false;
  79. break;
  80. }
  81. }
  82. if (match)
  83. {
  84. selectedESize = eSize;
  85. repetitions = 64 / eSize;
  86. onesCount = BitOperations.PopCount(eValue);
  87. break;
  88. }
  89. }
  90. }
  91. // Find rotation. We have two cases, one where the highest bit is 0
  92. // and one where it is 1.
  93. // If it's 1, we just need to count the number of 1 bits on the MSB to find the right rotation.
  94. // If it's 0, we just need to count the number of 0 bits on the LSB to find the left rotation,
  95. // then we can convert it to the right rotation shift by subtracting the value from the element size.
  96. int rotation;
  97. long vHigh = (long)(value << (64 - selectedESize));
  98. if (vHigh < 0)
  99. {
  100. rotation = BitOperations.LeadingZeroCount(~(ulong)vHigh);
  101. }
  102. else
  103. {
  104. rotation = (selectedESize - BitOperations.TrailingZeroCount(value)) & (selectedESize - 1);
  105. }
  106. // Reconstruct value and see if it matches. If not, we can't encode.
  107. ulong reconstructed = onesCount == 64 ? ulong.MaxValue : RotateRight((1UL << onesCount) - 1, rotation, selectedESize);
  108. for (int bit = 32; bit >= selectedESize; bit >>= 1)
  109. {
  110. reconstructed |= reconstructed << bit;
  111. }
  112. if (reconstructed != value || onesCount == 0)
  113. {
  114. immN = 0;
  115. immS = 0;
  116. immR = 0;
  117. return false;
  118. }
  119. immR = rotation;
  120. // immN indicates that there are no repetitions.
  121. // The MSB of immS indicates the amount of repetitions, and the LSB the number of bits set.
  122. if (repetitions == 1)
  123. {
  124. immN = 1;
  125. immS = 0;
  126. }
  127. else
  128. {
  129. immN = 0;
  130. immS = (0xf80 >> BitOperations.Log2((uint)repetitions)) & 0x3f;
  131. }
  132. immS |= onesCount - 1;
  133. return true;
  134. }
  135. private static int CountSequence(ulong value)
  136. {
  137. return BitOperations.TrailingZeroCount(value) + BitOperations.TrailingZeroCount(~value);
  138. }
  139. private static ulong RotateRight(ulong bits, int shift, int size)
  140. {
  141. return (bits >> shift) | ((bits << (size - shift)) & (size == 64 ? ulong.MaxValue : (1UL << size) - 1));
  142. }
  143. }
  144. }