LiveInterval.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. namespace ARMeilleure.CodeGen.RegisterAllocators
  6. {
  7. unsafe readonly struct LiveInterval : IComparable<LiveInterval>
  8. {
  9. public const int NotFound = -1;
  10. private struct Data
  11. {
  12. public int End;
  13. public int SpillOffset;
  14. public LiveRange FirstRange;
  15. public LiveRange PrevRange;
  16. public LiveRange CurrRange;
  17. public LiveInterval Parent;
  18. public UseList Uses;
  19. public LiveIntervalList Children;
  20. public Operand Local;
  21. public Register Register;
  22. public bool IsFixed;
  23. public bool IsFixedAndUsed;
  24. }
  25. private readonly Data* _data;
  26. private ref int End => ref _data->End;
  27. private ref LiveRange FirstRange => ref _data->FirstRange;
  28. private ref LiveRange CurrRange => ref _data->CurrRange;
  29. private ref LiveRange PrevRange => ref _data->PrevRange;
  30. private ref LiveInterval Parent => ref _data->Parent;
  31. private ref UseList Uses => ref _data->Uses;
  32. private ref LiveIntervalList Children => ref _data->Children;
  33. public Operand Local => _data->Local;
  34. public ref Register Register => ref _data->Register;
  35. public ref int SpillOffset => ref _data->SpillOffset;
  36. public bool IsFixed => _data->IsFixed;
  37. public ref bool IsFixedAndUsed => ref _data->IsFixedAndUsed;
  38. public bool IsEmpty => FirstRange == default;
  39. public bool IsSplit => Children.Count != 0;
  40. public bool IsSpilled => SpillOffset != -1;
  41. public int UsesCount => Uses.Count;
  42. public LiveInterval(Operand local = default, LiveInterval parent = default)
  43. {
  44. _data = Allocators.LiveIntervals.Allocate<Data>();
  45. *_data = default;
  46. _data->IsFixed = false;
  47. _data->Local = local;
  48. Parent = parent == default ? this : parent;
  49. Uses = new UseList();
  50. Children = new LiveIntervalList();
  51. FirstRange = default;
  52. CurrRange = default;
  53. PrevRange = default;
  54. SpillOffset = -1;
  55. }
  56. public LiveInterval(Register register) : this(local: default, parent: default)
  57. {
  58. _data->IsFixed = true;
  59. Register = register;
  60. }
  61. public void Reset()
  62. {
  63. PrevRange = default;
  64. CurrRange = FirstRange;
  65. }
  66. public void Forward(int position)
  67. {
  68. LiveRange prev = PrevRange;
  69. LiveRange curr = CurrRange;
  70. while (curr != default && curr.Start < position && !curr.Overlaps(position))
  71. {
  72. prev = curr;
  73. curr = curr.Next;
  74. }
  75. PrevRange = prev;
  76. CurrRange = curr;
  77. }
  78. public int GetStart()
  79. {
  80. Debug.Assert(!IsEmpty, "Empty LiveInterval cannot have a start position.");
  81. return FirstRange.Start;
  82. }
  83. public void SetStart(int position)
  84. {
  85. if (FirstRange != default)
  86. {
  87. Debug.Assert(position != FirstRange.End);
  88. FirstRange.Start = position;
  89. }
  90. else
  91. {
  92. FirstRange = new LiveRange(position, position + 1);
  93. End = position + 1;
  94. }
  95. }
  96. public int GetEnd()
  97. {
  98. Debug.Assert(!IsEmpty, "Empty LiveInterval cannot have an end position.");
  99. return End;
  100. }
  101. public void AddRange(int start, int end)
  102. {
  103. Debug.Assert(start < end, $"Invalid range start position {start}, {end}");
  104. if (FirstRange != default)
  105. {
  106. // If the new range ends exactly where the first range start, then coalesce together.
  107. if (end == FirstRange.Start)
  108. {
  109. FirstRange.Start = start;
  110. return;
  111. }
  112. // If the new range is already contained, then coalesce together.
  113. else if (FirstRange.Overlaps(start, end))
  114. {
  115. FirstRange.Start = Math.Min(FirstRange.Start, start);
  116. FirstRange.End = Math.Max(FirstRange.End, end);
  117. End = Math.Max(End, end);
  118. Debug.Assert(FirstRange.Next == default || !FirstRange.Overlaps(FirstRange.Next));
  119. return;
  120. }
  121. }
  122. FirstRange = new LiveRange(start, end, FirstRange);
  123. End = Math.Max(End, end);
  124. Debug.Assert(FirstRange.Next == default || !FirstRange.Overlaps(FirstRange.Next));
  125. }
  126. public void AddUsePosition(int position)
  127. {
  128. Uses.Add(position);
  129. }
  130. public bool Overlaps(int position)
  131. {
  132. LiveRange curr = CurrRange;
  133. while (curr != default && curr.Start <= position)
  134. {
  135. if (curr.Overlaps(position))
  136. {
  137. return true;
  138. }
  139. curr = curr.Next;
  140. }
  141. return false;
  142. }
  143. public bool Overlaps(LiveInterval other)
  144. {
  145. return GetOverlapPosition(other) != NotFound;
  146. }
  147. public int GetOverlapPosition(LiveInterval other)
  148. {
  149. LiveRange a = CurrRange;
  150. LiveRange b = other.CurrRange;
  151. while (a != default)
  152. {
  153. while (b != default && b.Start < a.Start)
  154. {
  155. if (a.Overlaps(b))
  156. {
  157. return a.Start;
  158. }
  159. b = b.Next;
  160. }
  161. if (b == default)
  162. {
  163. break;
  164. }
  165. else if (a.Overlaps(b))
  166. {
  167. return a.Start;
  168. }
  169. a = a.Next;
  170. }
  171. return NotFound;
  172. }
  173. public ReadOnlySpan<LiveInterval> SplitChildren()
  174. {
  175. return Parent.Children.Span;
  176. }
  177. public ReadOnlySpan<int> UsePositions()
  178. {
  179. return Uses.Span;
  180. }
  181. public int FirstUse()
  182. {
  183. return Uses.FirstUse;
  184. }
  185. public int NextUseAfter(int position)
  186. {
  187. return Uses.NextUse(position);
  188. }
  189. public LiveInterval Split(int position)
  190. {
  191. LiveInterval result = new(Local, Parent);
  192. result.End = End;
  193. LiveRange prev = PrevRange;
  194. LiveRange curr = CurrRange;
  195. while (curr != default && curr.Start < position && !curr.Overlaps(position))
  196. {
  197. prev = curr;
  198. curr = curr.Next;
  199. }
  200. if (curr.Start >= position)
  201. {
  202. prev.Next = default;
  203. result.FirstRange = curr;
  204. End = prev.End;
  205. }
  206. else
  207. {
  208. result.FirstRange = new LiveRange(position, curr.End, curr.Next);
  209. curr.End = position;
  210. curr.Next = default;
  211. End = curr.End;
  212. }
  213. result.Uses = Uses.Split(position);
  214. AddSplitChild(result);
  215. Debug.Assert(!IsEmpty, "Left interval is empty after split.");
  216. Debug.Assert(!result.IsEmpty, "Right interval is empty after split.");
  217. // Make sure the iterator in the new split is pointing to the start.
  218. result.Reset();
  219. return result;
  220. }
  221. private void AddSplitChild(LiveInterval child)
  222. {
  223. Debug.Assert(!child.IsEmpty, "Trying to insert an empty interval.");
  224. Parent.Children.Add(child);
  225. }
  226. public LiveInterval GetSplitChild(int position)
  227. {
  228. if (Overlaps(position))
  229. {
  230. return this;
  231. }
  232. foreach (LiveInterval splitChild in SplitChildren())
  233. {
  234. if (splitChild.Overlaps(position))
  235. {
  236. return splitChild;
  237. }
  238. else if (splitChild.GetStart() > position)
  239. {
  240. break;
  241. }
  242. }
  243. return default;
  244. }
  245. public bool TrySpillWithSiblingOffset()
  246. {
  247. foreach (LiveInterval splitChild in SplitChildren())
  248. {
  249. if (splitChild.IsSpilled)
  250. {
  251. Spill(splitChild.SpillOffset);
  252. return true;
  253. }
  254. }
  255. return false;
  256. }
  257. public void Spill(int offset)
  258. {
  259. SpillOffset = offset;
  260. }
  261. public int CompareTo(LiveInterval interval)
  262. {
  263. if (FirstRange == default || interval.FirstRange == default)
  264. {
  265. return 0;
  266. }
  267. return GetStart().CompareTo(interval.GetStart());
  268. }
  269. public bool Equals(LiveInterval interval)
  270. {
  271. return interval._data == _data;
  272. }
  273. public override bool Equals(object obj)
  274. {
  275. return obj is LiveInterval interval && Equals(interval);
  276. }
  277. public static bool operator ==(LiveInterval a, LiveInterval b)
  278. {
  279. return a.Equals(b);
  280. }
  281. public static bool operator !=(LiveInterval a, LiveInterval b)
  282. {
  283. return !a.Equals(b);
  284. }
  285. public override int GetHashCode()
  286. {
  287. return HashCode.Combine((IntPtr)_data);
  288. }
  289. public override string ToString()
  290. {
  291. LiveInterval self = this;
  292. IEnumerable<string> GetRanges()
  293. {
  294. LiveRange curr = self.CurrRange;
  295. while (curr != default)
  296. {
  297. if (curr == self.CurrRange)
  298. {
  299. yield return "*" + curr;
  300. }
  301. else
  302. {
  303. yield return curr.ToString();
  304. }
  305. curr = curr.Next;
  306. }
  307. }
  308. return string.Join(", ", GetRanges());
  309. }
  310. }
  311. }