LiveInterval.cs 10 KB

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