PreAllocatorSystemV.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. using ARMeilleure.CodeGen.RegisterAllocators;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  8. using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
  9. namespace ARMeilleure.CodeGen.X86
  10. {
  11. class PreAllocatorSystemV : PreAllocator
  12. {
  13. public static void InsertCallCopies(IntrusiveList<Operation> nodes, Operation node)
  14. {
  15. Operand dest = node.Destination;
  16. List<Operand> sources = new List<Operand>
  17. {
  18. node.GetSource(0)
  19. };
  20. int argsCount = node.SourcesCount - 1;
  21. int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
  22. int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
  23. int intCount = 0;
  24. int vecCount = 0;
  25. int stackOffset = 0;
  26. for (int index = 0; index < argsCount; index++)
  27. {
  28. Operand source = node.GetSource(index + 1);
  29. bool passOnReg;
  30. if (source.Type.IsInteger())
  31. {
  32. passOnReg = intCount < intMax;
  33. }
  34. else if (source.Type == OperandType.V128)
  35. {
  36. passOnReg = intCount + 1 < intMax;
  37. }
  38. else
  39. {
  40. passOnReg = vecCount < vecMax;
  41. }
  42. if (source.Type == OperandType.V128 && passOnReg)
  43. {
  44. // V128 is a struct, we pass each half on a GPR if possible.
  45. Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
  46. Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
  47. nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
  48. nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
  49. continue;
  50. }
  51. if (passOnReg)
  52. {
  53. Operand argReg = source.Type.IsInteger()
  54. ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
  55. : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
  56. Operation copyOp = Operation(Instruction.Copy, argReg, source);
  57. InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
  58. sources.Add(argReg);
  59. }
  60. else
  61. {
  62. Operand offset = Const(stackOffset);
  63. Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
  64. InsertConstantRegCopies(nodes, nodes.AddBefore(node, spillOp));
  65. stackOffset += source.Type.GetSizeInBytes();
  66. }
  67. }
  68. node.SetSources(sources.ToArray());
  69. if (dest != default)
  70. {
  71. if (dest.Type == OperandType.V128)
  72. {
  73. Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
  74. Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
  75. Operation operation = node;
  76. node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
  77. nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
  78. operation.Destination = default;
  79. }
  80. else
  81. {
  82. Operand retReg = dest.Type.IsInteger()
  83. ? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
  84. : Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
  85. Operation copyOp = Operation(Instruction.Copy, dest, retReg);
  86. nodes.AddAfter(node, copyOp);
  87. node.Destination = retReg;
  88. }
  89. }
  90. }
  91. public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
  92. {
  93. List<Operand> sources = new List<Operand>
  94. {
  95. node.GetSource(0)
  96. };
  97. int argsCount = node.SourcesCount - 1;
  98. int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
  99. int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
  100. int intCount = 0;
  101. int vecCount = 0;
  102. // Handle arguments passed on registers.
  103. for (int index = 0; index < argsCount; index++)
  104. {
  105. Operand source = node.GetSource(1 + index);
  106. bool passOnReg;
  107. if (source.Type.IsInteger())
  108. {
  109. passOnReg = intCount + 1 < intMax;
  110. }
  111. else
  112. {
  113. passOnReg = vecCount < vecMax;
  114. }
  115. if (source.Type == OperandType.V128 && passOnReg)
  116. {
  117. // V128 is a struct, we pass each half on a GPR if possible.
  118. Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
  119. Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
  120. nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
  121. nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
  122. continue;
  123. }
  124. if (passOnReg)
  125. {
  126. Operand argReg = source.Type.IsInteger()
  127. ? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
  128. : Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
  129. Operation copyOp = Operation(Instruction.Copy, argReg, source);
  130. InsertConstantRegCopies(nodes, nodes.AddBefore(node, copyOp));
  131. sources.Add(argReg);
  132. }
  133. else
  134. {
  135. throw new NotImplementedException("Spilling is not currently supported for tail calls. (too many arguments)");
  136. }
  137. }
  138. // The target address must be on the return registers, since we
  139. // don't return anything and it is guaranteed to not be a
  140. // callee saved register (which would be trashed on the epilogue).
  141. Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
  142. Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
  143. nodes.AddBefore(node, addrCopyOp);
  144. sources[0] = retReg;
  145. node.SetSources(sources.ToArray());
  146. }
  147. public static Operation InsertLoadArgumentCopy(
  148. CompilerContext cctx,
  149. ref Span<Operation> buffer,
  150. IntrusiveList<Operation> nodes,
  151. Operand[] preservedArgs,
  152. Operation node)
  153. {
  154. Operand source = node.GetSource(0);
  155. Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
  156. int index = source.AsInt32();
  157. int intCount = 0;
  158. int vecCount = 0;
  159. for (int cIndex = 0; cIndex < index; cIndex++)
  160. {
  161. OperandType argType = cctx.FuncArgTypes[cIndex];
  162. if (argType.IsInteger())
  163. {
  164. intCount++;
  165. }
  166. else if (argType == OperandType.V128)
  167. {
  168. intCount += 2;
  169. }
  170. else
  171. {
  172. vecCount++;
  173. }
  174. }
  175. bool passOnReg;
  176. if (source.Type.IsInteger())
  177. {
  178. passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount();
  179. }
  180. else if (source.Type == OperandType.V128)
  181. {
  182. passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount();
  183. }
  184. else
  185. {
  186. passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount();
  187. }
  188. if (passOnReg)
  189. {
  190. Operand dest = node.Destination;
  191. if (preservedArgs[index] == default)
  192. {
  193. if (dest.Type == OperandType.V128)
  194. {
  195. // V128 is a struct, we pass each half on a GPR if possible.
  196. Operand pArg = Local(OperandType.V128);
  197. Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
  198. Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
  199. Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
  200. Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
  201. cctx.Cfg.Entry.Operations.AddFirst(copyH);
  202. cctx.Cfg.Entry.Operations.AddFirst(copyL);
  203. preservedArgs[index] = pArg;
  204. }
  205. else
  206. {
  207. Operand pArg = Local(dest.Type);
  208. Operand argReg = dest.Type.IsInteger()
  209. ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
  210. : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
  211. Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
  212. cctx.Cfg.Entry.Operations.AddFirst(copyOp);
  213. preservedArgs[index] = pArg;
  214. }
  215. }
  216. Operation nextNode;
  217. if (dest.AssignmentsCount == 1)
  218. {
  219. // Let's propagate the argument if we can to avoid copies.
  220. PreAllocatorCommon.Propagate(ref buffer, dest, preservedArgs[index]);
  221. nextNode = node.ListNext;
  222. }
  223. else
  224. {
  225. Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
  226. nextNode = nodes.AddBefore(node, argCopyOp);
  227. }
  228. Delete(nodes, node);
  229. return nextNode;
  230. }
  231. else
  232. {
  233. // TODO: Pass on stack.
  234. return node;
  235. }
  236. }
  237. public static void InsertReturnCopy(IntrusiveList<Operation> nodes, Operation node)
  238. {
  239. if (node.SourcesCount == 0)
  240. {
  241. return;
  242. }
  243. Operand source = node.GetSource(0);
  244. if (source.Type == OperandType.V128)
  245. {
  246. Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
  247. Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
  248. nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
  249. nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
  250. }
  251. else
  252. {
  253. Operand retReg = source.Type.IsInteger()
  254. ? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
  255. : Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
  256. Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
  257. nodes.AddBefore(node, retCopyOp);
  258. }
  259. }
  260. }
  261. }