Operation.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. namespace ARMeilleure.IntermediateRepresentation
  5. {
  6. unsafe struct Operation : IEquatable<Operation>, IIntrusiveListNode<Operation>
  7. {
  8. internal struct Data
  9. {
  10. public ushort Instruction;
  11. public ushort Intrinsic;
  12. public ushort SourcesCount;
  13. public ushort DestinationsCount;
  14. public Operation ListPrevious;
  15. public Operation ListNext;
  16. public Operand* Destinations;
  17. public Operand* Sources;
  18. }
  19. private Data* _data;
  20. public Instruction Instruction
  21. {
  22. get => (Instruction)_data->Instruction;
  23. private set => _data->Instruction = (ushort)value;
  24. }
  25. public Intrinsic Intrinsic
  26. {
  27. get => (Intrinsic)_data->Intrinsic;
  28. private set => _data->Intrinsic = (ushort)value;
  29. }
  30. public Operation ListPrevious
  31. {
  32. get => _data->ListPrevious;
  33. set => _data->ListPrevious = value;
  34. }
  35. public Operation ListNext
  36. {
  37. get => _data->ListNext;
  38. set => _data->ListNext = value;
  39. }
  40. public Operand Destination
  41. {
  42. get => _data->DestinationsCount != 0 ? GetDestination(0) : default;
  43. set => SetDestination(value);
  44. }
  45. public int DestinationsCount => _data->DestinationsCount;
  46. public int SourcesCount => _data->SourcesCount;
  47. internal Span<Operand> DestinationsUnsafe => new(_data->Destinations, _data->DestinationsCount);
  48. internal Span<Operand> SourcesUnsafe => new(_data->Sources, _data->SourcesCount);
  49. public PhiOperation AsPhi()
  50. {
  51. Debug.Assert(Instruction == Instruction.Phi);
  52. return new PhiOperation(this);
  53. }
  54. public Operand GetDestination(int index)
  55. {
  56. return DestinationsUnsafe[index];
  57. }
  58. public Operand GetSource(int index)
  59. {
  60. return SourcesUnsafe[index];
  61. }
  62. public void SetDestination(int index, Operand dest)
  63. {
  64. ref Operand curDest = ref DestinationsUnsafe[index];
  65. RemoveAssignment(curDest);
  66. AddAssignment(dest);
  67. curDest = dest;
  68. }
  69. public void SetSource(int index, Operand src)
  70. {
  71. ref Operand curSrc = ref SourcesUnsafe[index];
  72. RemoveUse(curSrc);
  73. AddUse(src);
  74. curSrc = src;
  75. }
  76. private void RemoveOldDestinations()
  77. {
  78. for (int i = 0; i < _data->DestinationsCount; i++)
  79. {
  80. RemoveAssignment(_data->Destinations[i]);
  81. }
  82. }
  83. public void SetDestination(Operand dest)
  84. {
  85. RemoveOldDestinations();
  86. if (dest == default)
  87. {
  88. _data->DestinationsCount = 0;
  89. }
  90. else
  91. {
  92. EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, 1);
  93. _data->Destinations[0] = dest;
  94. AddAssignment(dest);
  95. }
  96. }
  97. public void SetDestinations(Operand[] dests)
  98. {
  99. RemoveOldDestinations();
  100. EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, dests.Length);
  101. for (int index = 0; index < dests.Length; index++)
  102. {
  103. Operand newOp = dests[index];
  104. _data->Destinations[index] = newOp;
  105. AddAssignment(newOp);
  106. }
  107. }
  108. private void RemoveOldSources()
  109. {
  110. for (int index = 0; index < _data->SourcesCount; index++)
  111. {
  112. RemoveUse(_data->Sources[index]);
  113. }
  114. }
  115. public void SetSource(Operand src)
  116. {
  117. RemoveOldSources();
  118. if (src == default)
  119. {
  120. _data->SourcesCount = 0;
  121. }
  122. else
  123. {
  124. EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, 1);
  125. _data->Sources[0] = src;
  126. AddUse(src);
  127. }
  128. }
  129. public void SetSources(Operand[] srcs)
  130. {
  131. RemoveOldSources();
  132. EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, srcs.Length);
  133. for (int index = 0; index < srcs.Length; index++)
  134. {
  135. Operand newOp = srcs[index];
  136. _data->Sources[index] = newOp;
  137. AddUse(newOp);
  138. }
  139. }
  140. public void TurnIntoCopy(Operand source)
  141. {
  142. Instruction = Instruction.Copy;
  143. SetSource(source);
  144. }
  145. private void AddAssignment(Operand op)
  146. {
  147. if (op != default)
  148. {
  149. op.AddAssignment(this);
  150. }
  151. }
  152. private void RemoveAssignment(Operand op)
  153. {
  154. if (op != default)
  155. {
  156. op.RemoveAssignment(this);
  157. }
  158. }
  159. private void AddUse(Operand op)
  160. {
  161. if (op != default)
  162. {
  163. op.AddUse(this);
  164. }
  165. }
  166. private void RemoveUse(Operand op)
  167. {
  168. if (op != default)
  169. {
  170. op.RemoveUse(this);
  171. }
  172. }
  173. public bool Equals(Operation operation)
  174. {
  175. return operation._data == _data;
  176. }
  177. public override bool Equals(object obj)
  178. {
  179. return obj is Operation operation && Equals(operation);
  180. }
  181. public override int GetHashCode()
  182. {
  183. return HashCode.Combine((IntPtr)_data);
  184. }
  185. public static bool operator ==(Operation a, Operation b)
  186. {
  187. return a.Equals(b);
  188. }
  189. public static bool operator !=(Operation a, Operation b)
  190. {
  191. return !a.Equals(b);
  192. }
  193. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  194. private static void EnsureCapacity(ref Operand* list, ref ushort capacity, int newCapacity)
  195. {
  196. if (newCapacity > ushort.MaxValue)
  197. {
  198. ThrowOverflow(newCapacity);
  199. }
  200. // We only need to allocate a new buffer if we're increasing the size.
  201. else if (newCapacity > capacity)
  202. {
  203. list = Allocators.References.Allocate<Operand>((uint)newCapacity);
  204. }
  205. capacity = (ushort)newCapacity;
  206. }
  207. private static void ThrowOverflow(int count) =>
  208. throw new OverflowException($"Exceeded maximum size for Source or Destinations. Required {count}.");
  209. public static class Factory
  210. {
  211. private static Operation Make(Instruction inst, int destCount, int srcCount)
  212. {
  213. Data* data = Allocators.Operations.Allocate<Data>();
  214. *data = default;
  215. Operation result = new();
  216. result._data = data;
  217. result.Instruction = inst;
  218. EnsureCapacity(ref result._data->Destinations, ref result._data->DestinationsCount, destCount);
  219. EnsureCapacity(ref result._data->Sources, ref result._data->SourcesCount, srcCount);
  220. result.DestinationsUnsafe.Clear();
  221. result.SourcesUnsafe.Clear();
  222. return result;
  223. }
  224. public static Operation Operation(Instruction inst, Operand dest)
  225. {
  226. Operation result = Make(inst, 0, 0);
  227. result.SetDestination(dest);
  228. return result;
  229. }
  230. public static Operation Operation(Instruction inst, Operand dest, Operand src0)
  231. {
  232. Operation result = Make(inst, 0, 1);
  233. result.SetDestination(dest);
  234. result.SetSource(0, src0);
  235. return result;
  236. }
  237. public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1)
  238. {
  239. Operation result = Make(inst, 0, 2);
  240. result.SetDestination(dest);
  241. result.SetSource(0, src0);
  242. result.SetSource(1, src1);
  243. return result;
  244. }
  245. public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1, Operand src2)
  246. {
  247. Operation result = Make(inst, 0, 3);
  248. result.SetDestination(dest);
  249. result.SetSource(0, src0);
  250. result.SetSource(1, src1);
  251. result.SetSource(2, src2);
  252. return result;
  253. }
  254. public static Operation Operation(Instruction inst, Operand dest, int srcCount)
  255. {
  256. Operation result = Make(inst, 0, srcCount);
  257. result.SetDestination(dest);
  258. return result;
  259. }
  260. public static Operation Operation(Instruction inst, Operand dest, Operand[] srcs)
  261. {
  262. Operation result = Make(inst, 0, srcs.Length);
  263. result.SetDestination(dest);
  264. for (int index = 0; index < srcs.Length; index++)
  265. {
  266. result.SetSource(index, srcs[index]);
  267. }
  268. return result;
  269. }
  270. public static Operation Operation(Intrinsic intrin, Operand dest, params Operand[] srcs)
  271. {
  272. Operation result = Make(Instruction.Extended, 0, srcs.Length);
  273. result.Intrinsic = intrin;
  274. result.SetDestination(dest);
  275. for (int index = 0; index < srcs.Length; index++)
  276. {
  277. result.SetSource(index, srcs[index]);
  278. }
  279. return result;
  280. }
  281. public static Operation Operation(Instruction inst, Operand[] dests, Operand[] srcs)
  282. {
  283. Operation result = Make(inst, dests.Length, srcs.Length);
  284. for (int index = 0; index < dests.Length; index++)
  285. {
  286. result.SetDestination(index, dests[index]);
  287. }
  288. for (int index = 0; index < srcs.Length; index++)
  289. {
  290. result.SetSource(index, srcs[index]);
  291. }
  292. return result;
  293. }
  294. public static Operation PhiOperation(Operand dest, int srcCount)
  295. {
  296. return Operation(Instruction.Phi, dest, srcCount * 2);
  297. }
  298. }
  299. }
  300. }