LiveInterval.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. using ARMeilleure.Common;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. namespace ARMeilleure.CodeGen.RegisterAllocators
  8. {
  9. class LiveInterval : IComparable<LiveInterval>
  10. {
  11. public const int NotFound = -1;
  12. private LiveInterval _parent;
  13. private SortedIntegerList _usePositions;
  14. public int UsesCount => _usePositions.Count;
  15. private List<LiveRange> _ranges;
  16. private SortedList<int, LiveInterval> _childs;
  17. public bool IsSplit => _childs.Count != 0;
  18. public Operand Local { get; }
  19. public Register Register { get; set; }
  20. public int SpillOffset { get; private set; }
  21. public bool IsSpilled => SpillOffset != -1;
  22. public bool IsFixed { get; }
  23. public bool IsEmpty => _ranges.Count == 0;
  24. public LiveInterval(Operand local = null, LiveInterval parent = null)
  25. {
  26. Local = local;
  27. _parent = parent ?? this;
  28. _usePositions = new SortedIntegerList();
  29. _ranges = new List<LiveRange>();
  30. _childs = new SortedList<int, LiveInterval>();
  31. SpillOffset = -1;
  32. }
  33. public LiveInterval(Register register) : this()
  34. {
  35. IsFixed = true;
  36. Register = register;
  37. }
  38. public void SetStart(int position)
  39. {
  40. if (_ranges.Count != 0)
  41. {
  42. Debug.Assert(position != _ranges[0].End);
  43. _ranges[0] = new LiveRange(position, _ranges[0].End);
  44. }
  45. else
  46. {
  47. _ranges.Add(new LiveRange(position, position + 1));
  48. }
  49. }
  50. public int GetStart()
  51. {
  52. if (_ranges.Count == 0)
  53. {
  54. throw new InvalidOperationException("Empty interval.");
  55. }
  56. return _ranges[0].Start;
  57. }
  58. public void SetEnd(int position)
  59. {
  60. if (_ranges.Count != 0)
  61. {
  62. int lastIdx = _ranges.Count - 1;
  63. Debug.Assert(position != _ranges[lastIdx].Start);
  64. _ranges[lastIdx] = new LiveRange(_ranges[lastIdx].Start, position);
  65. }
  66. else
  67. {
  68. _ranges.Add(new LiveRange(position, position + 1));
  69. }
  70. }
  71. public int GetEnd()
  72. {
  73. if (_ranges.Count == 0)
  74. {
  75. throw new InvalidOperationException("Empty interval.");
  76. }
  77. return _ranges[_ranges.Count - 1].End;
  78. }
  79. public void AddRange(int start, int end)
  80. {
  81. if (start >= end)
  82. {
  83. throw new ArgumentException("Invalid range start position " + start + ", " + end);
  84. }
  85. int index = _ranges.BinarySearch(new LiveRange(start, end));
  86. if (index >= 0)
  87. {
  88. // New range insersects with an existing range, we need to remove
  89. // all the intersecting ranges before adding the new one.
  90. // We also extend the new range as needed, based on the values of
  91. // the existing ranges being removed.
  92. int lIndex = index;
  93. int rIndex = index;
  94. while (lIndex > 0 && _ranges[lIndex - 1].End >= start)
  95. {
  96. lIndex--;
  97. }
  98. while (rIndex + 1 < _ranges.Count && _ranges[rIndex + 1].Start <= end)
  99. {
  100. rIndex++;
  101. }
  102. if (start > _ranges[lIndex].Start)
  103. {
  104. start = _ranges[lIndex].Start;
  105. }
  106. if (end < _ranges[rIndex].End)
  107. {
  108. end = _ranges[rIndex].End;
  109. }
  110. _ranges.RemoveRange(lIndex, (rIndex - lIndex) + 1);
  111. InsertRange(lIndex, start, end);
  112. }
  113. else
  114. {
  115. InsertRange(~index, start, end);
  116. }
  117. }
  118. private void InsertRange(int index, int start, int end)
  119. {
  120. // Here we insert a new range on the ranges list.
  121. // If possible, we extend an existing range rather than inserting a new one.
  122. // We can extend an existing range if any of the following conditions are true:
  123. // - The new range starts right after the end of the previous range on the list.
  124. // - The new range ends right before the start of the next range on the list.
  125. // If both cases are true, we can extend either one. We prefer to extend the
  126. // previous range, and then remove the next one, but theres no specific reason
  127. // for that, extending either one will do.
  128. int? extIndex = null;
  129. if (index > 0 && _ranges[index - 1].End == start)
  130. {
  131. start = _ranges[index - 1].Start;
  132. extIndex = index - 1;
  133. }
  134. if (index < _ranges.Count && _ranges[index].Start == end)
  135. {
  136. end = _ranges[index].End;
  137. if (extIndex.HasValue)
  138. {
  139. _ranges.RemoveAt(index);
  140. }
  141. else
  142. {
  143. extIndex = index;
  144. }
  145. }
  146. if (extIndex.HasValue)
  147. {
  148. _ranges[extIndex.Value] = new LiveRange(start, end);
  149. }
  150. else
  151. {
  152. _ranges.Insert(index, new LiveRange(start, end));
  153. }
  154. }
  155. public void AddUsePosition(int position)
  156. {
  157. // Inserts are in descending order, but ascending is faster for SortedIntegerList<>.
  158. // We flip the ordering, then iterate backwards when using the final list.
  159. _usePositions.Add(-position);
  160. }
  161. public bool Overlaps(int position)
  162. {
  163. return _ranges.BinarySearch(new LiveRange(position, position + 1)) >= 0;
  164. }
  165. public bool Overlaps(LiveInterval other)
  166. {
  167. foreach (LiveRange range in other._ranges)
  168. {
  169. if (_ranges.BinarySearch(range) >= 0)
  170. {
  171. return true;
  172. }
  173. }
  174. return false;
  175. }
  176. public int GetOverlapPosition(LiveInterval other)
  177. {
  178. foreach (LiveRange range in other._ranges)
  179. {
  180. int overlapIndex = _ranges.BinarySearch(range);
  181. if (overlapIndex >= 0)
  182. {
  183. // It's possible that we have multiple overlaps within a single interval,
  184. // in this case, we pick the one with the lowest start position, since
  185. // we return the first overlap position.
  186. while (overlapIndex > 0 && _ranges[overlapIndex - 1].End > range.Start)
  187. {
  188. overlapIndex--;
  189. }
  190. LiveRange overlappingRange = _ranges[overlapIndex];
  191. return overlappingRange.Start;
  192. }
  193. }
  194. return NotFound;
  195. }
  196. public IEnumerable<LiveInterval> SplitChilds()
  197. {
  198. return _childs.Values;
  199. }
  200. public IList<int> UsePositions()
  201. {
  202. return _usePositions.GetList();
  203. }
  204. public int FirstUse()
  205. {
  206. if (_usePositions.Count == 0)
  207. {
  208. return NotFound;
  209. }
  210. return -_usePositions.Last();
  211. }
  212. public int NextUseAfter(int position)
  213. {
  214. int index = _usePositions.FindLessEqualIndex(-position);
  215. return (index >= 0) ? -_usePositions[index] : NotFound;
  216. }
  217. public void RemoveAfter(int position)
  218. {
  219. int index = _usePositions.FindLessEqualIndex(-position);
  220. _usePositions.RemoveRange(0, index + 1);
  221. }
  222. public LiveInterval Split(int position)
  223. {
  224. LiveInterval right = new LiveInterval(Local, _parent);
  225. int splitIndex = 0;
  226. for (; splitIndex < _ranges.Count; splitIndex++)
  227. {
  228. LiveRange range = _ranges[splitIndex];
  229. if (position > range.Start && position <= range.End)
  230. {
  231. right._ranges.Add(new LiveRange(position, range.End));
  232. range = new LiveRange(range.Start, position);
  233. _ranges[splitIndex++] = range;
  234. break;
  235. }
  236. if (range.Start >= position)
  237. {
  238. break;
  239. }
  240. }
  241. if (splitIndex < _ranges.Count)
  242. {
  243. int count = _ranges.Count - splitIndex;
  244. right._ranges.AddRange(_ranges.GetRange(splitIndex, count));
  245. _ranges.RemoveRange(splitIndex, count);
  246. }
  247. int addAfter = _usePositions.FindLessEqualIndex(-position);
  248. for (int index = addAfter; index >= 0; index--)
  249. {
  250. int usePosition = _usePositions[index];
  251. right._usePositions.Add(usePosition);
  252. }
  253. RemoveAfter(position);
  254. Debug.Assert(_ranges.Count != 0, "Left interval is empty after split.");
  255. Debug.Assert(right._ranges.Count != 0, "Right interval is empty after split.");
  256. AddSplitChild(right);
  257. return right;
  258. }
  259. private void AddSplitChild(LiveInterval child)
  260. {
  261. Debug.Assert(!child.IsEmpty, "Trying to insert a empty interval.");
  262. _parent._childs.Add(child.GetStart(), child);
  263. }
  264. public LiveInterval GetSplitChild(int position)
  265. {
  266. if (Overlaps(position))
  267. {
  268. return this;
  269. }
  270. foreach (LiveInterval splitChild in _childs.Values)
  271. {
  272. if (splitChild.Overlaps(position))
  273. {
  274. return splitChild;
  275. }
  276. }
  277. return null;
  278. }
  279. public bool TrySpillWithSiblingOffset()
  280. {
  281. foreach (LiveInterval splitChild in _parent._childs.Values)
  282. {
  283. if (splitChild.IsSpilled)
  284. {
  285. Spill(splitChild.SpillOffset);
  286. return true;
  287. }
  288. }
  289. return false;
  290. }
  291. public void Spill(int offset)
  292. {
  293. SpillOffset = offset;
  294. }
  295. public int CompareTo(LiveInterval other)
  296. {
  297. if (_ranges.Count == 0 || other._ranges.Count == 0)
  298. {
  299. return _ranges.Count.CompareTo(other._ranges.Count);
  300. }
  301. return _ranges[0].Start.CompareTo(other._ranges[0].Start);
  302. }
  303. public override string ToString()
  304. {
  305. return string.Join("; ", _ranges);
  306. }
  307. }
  308. }