LiveInterval.cs 11 KB

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