ConstantFolding.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  4. namespace ARMeilleure.CodeGen.Optimizations
  5. {
  6. static class ConstantFolding
  7. {
  8. public static void RunPass(Operation operation)
  9. {
  10. if (operation.Destination == default || operation.SourcesCount == 0)
  11. {
  12. return;
  13. }
  14. if (!AreAllSourcesConstant(operation))
  15. {
  16. return;
  17. }
  18. OperandType type = operation.Destination.Type;
  19. switch (operation.Instruction)
  20. {
  21. case Instruction.Add:
  22. if (operation.GetSource(0).Relocatable ||
  23. operation.GetSource(1).Relocatable)
  24. {
  25. break;
  26. }
  27. if (type == OperandType.I32)
  28. {
  29. EvaluateBinaryI32(operation, (x, y) => x + y);
  30. }
  31. else if (type == OperandType.I64)
  32. {
  33. EvaluateBinaryI64(operation, (x, y) => x + y);
  34. }
  35. break;
  36. case Instruction.BitwiseAnd:
  37. if (type == OperandType.I32)
  38. {
  39. EvaluateBinaryI32(operation, (x, y) => x & y);
  40. }
  41. else if (type == OperandType.I64)
  42. {
  43. EvaluateBinaryI64(operation, (x, y) => x & y);
  44. }
  45. break;
  46. case Instruction.BitwiseExclusiveOr:
  47. if (type == OperandType.I32)
  48. {
  49. EvaluateBinaryI32(operation, (x, y) => x ^ y);
  50. }
  51. else if (type == OperandType.I64)
  52. {
  53. EvaluateBinaryI64(operation, (x, y) => x ^ y);
  54. }
  55. break;
  56. case Instruction.BitwiseNot:
  57. if (type == OperandType.I32)
  58. {
  59. EvaluateUnaryI32(operation, (x) => ~x);
  60. }
  61. else if (type == OperandType.I64)
  62. {
  63. EvaluateUnaryI64(operation, (x) => ~x);
  64. }
  65. break;
  66. case Instruction.BitwiseOr:
  67. if (type == OperandType.I32)
  68. {
  69. EvaluateBinaryI32(operation, (x, y) => x | y);
  70. }
  71. else if (type == OperandType.I64)
  72. {
  73. EvaluateBinaryI64(operation, (x, y) => x | y);
  74. }
  75. break;
  76. case Instruction.ConvertI64ToI32:
  77. if (type == OperandType.I32)
  78. {
  79. EvaluateUnaryI32(operation, (x) => x);
  80. }
  81. break;
  82. case Instruction.Compare:
  83. if (type == OperandType.I32 &&
  84. operation.GetSource(0).Type == type &&
  85. operation.GetSource(1).Type == type)
  86. {
  87. switch ((Comparison)operation.GetSource(2).Value)
  88. {
  89. case Comparison.Equal:
  90. EvaluateBinaryI32(operation, (x, y) => x == y ? 1 : 0);
  91. break;
  92. case Comparison.NotEqual:
  93. EvaluateBinaryI32(operation, (x, y) => x != y ? 1 : 0);
  94. break;
  95. case Comparison.Greater:
  96. EvaluateBinaryI32(operation, (x, y) => x > y ? 1 : 0);
  97. break;
  98. case Comparison.LessOrEqual:
  99. EvaluateBinaryI32(operation, (x, y) => x <= y ? 1 : 0);
  100. break;
  101. case Comparison.GreaterUI:
  102. EvaluateBinaryI32(operation, (x, y) => (uint)x > (uint)y ? 1 : 0);
  103. break;
  104. case Comparison.LessOrEqualUI:
  105. EvaluateBinaryI32(operation, (x, y) => (uint)x <= (uint)y ? 1 : 0);
  106. break;
  107. case Comparison.GreaterOrEqual:
  108. EvaluateBinaryI32(operation, (x, y) => x >= y ? 1 : 0);
  109. break;
  110. case Comparison.Less:
  111. EvaluateBinaryI32(operation, (x, y) => x < y ? 1 : 0);
  112. break;
  113. case Comparison.GreaterOrEqualUI:
  114. EvaluateBinaryI32(operation, (x, y) => (uint)x >= (uint)y ? 1 : 0);
  115. break;
  116. case Comparison.LessUI:
  117. EvaluateBinaryI32(operation, (x, y) => (uint)x < (uint)y ? 1 : 0);
  118. break;
  119. }
  120. }
  121. break;
  122. case Instruction.Copy:
  123. if (type == OperandType.I32)
  124. {
  125. EvaluateUnaryI32(operation, (x) => x);
  126. }
  127. else if (type == OperandType.I64)
  128. {
  129. EvaluateUnaryI64(operation, (x) => x);
  130. }
  131. break;
  132. case Instruction.Divide:
  133. if (type == OperandType.I32)
  134. {
  135. EvaluateBinaryI32(operation, (x, y) => y != 0 ? x / y : 0);
  136. }
  137. else if (type == OperandType.I64)
  138. {
  139. EvaluateBinaryI64(operation, (x, y) => y != 0 ? x / y : 0);
  140. }
  141. break;
  142. case Instruction.DivideUI:
  143. if (type == OperandType.I32)
  144. {
  145. EvaluateBinaryI32(operation, (x, y) => y != 0 ? (int)((uint)x / (uint)y) : 0);
  146. }
  147. else if (type == OperandType.I64)
  148. {
  149. EvaluateBinaryI64(operation, (x, y) => y != 0 ? (long)((ulong)x / (ulong)y) : 0);
  150. }
  151. break;
  152. case Instruction.Multiply:
  153. if (type == OperandType.I32)
  154. {
  155. EvaluateBinaryI32(operation, (x, y) => x * y);
  156. }
  157. else if (type == OperandType.I64)
  158. {
  159. EvaluateBinaryI64(operation, (x, y) => x * y);
  160. }
  161. break;
  162. case Instruction.Negate:
  163. if (type == OperandType.I32)
  164. {
  165. EvaluateUnaryI32(operation, (x) => -x);
  166. }
  167. else if (type == OperandType.I64)
  168. {
  169. EvaluateUnaryI64(operation, (x) => -x);
  170. }
  171. break;
  172. case Instruction.ShiftLeft:
  173. if (type == OperandType.I32)
  174. {
  175. EvaluateBinaryI32(operation, (x, y) => x << y);
  176. }
  177. else if (type == OperandType.I64)
  178. {
  179. EvaluateBinaryI64(operation, (x, y) => x << (int)y);
  180. }
  181. break;
  182. case Instruction.ShiftRightSI:
  183. if (type == OperandType.I32)
  184. {
  185. EvaluateBinaryI32(operation, (x, y) => x >> y);
  186. }
  187. else if (type == OperandType.I64)
  188. {
  189. EvaluateBinaryI64(operation, (x, y) => x >> (int)y);
  190. }
  191. break;
  192. case Instruction.ShiftRightUI:
  193. if (type == OperandType.I32)
  194. {
  195. EvaluateBinaryI32(operation, (x, y) => (int)((uint)x >> y));
  196. }
  197. else if (type == OperandType.I64)
  198. {
  199. EvaluateBinaryI64(operation, (x, y) => (long)((ulong)x >> (int)y));
  200. }
  201. break;
  202. case Instruction.SignExtend16:
  203. if (type == OperandType.I32)
  204. {
  205. EvaluateUnaryI32(operation, (x) => (short)x);
  206. }
  207. else if (type == OperandType.I64)
  208. {
  209. EvaluateUnaryI64(operation, (x) => (short)x);
  210. }
  211. break;
  212. case Instruction.SignExtend32:
  213. if (type == OperandType.I32)
  214. {
  215. EvaluateUnaryI32(operation, (x) => x);
  216. }
  217. else if (type == OperandType.I64)
  218. {
  219. EvaluateUnaryI64(operation, (x) => (int)x);
  220. }
  221. break;
  222. case Instruction.SignExtend8:
  223. if (type == OperandType.I32)
  224. {
  225. EvaluateUnaryI32(operation, (x) => (sbyte)x);
  226. }
  227. else if (type == OperandType.I64)
  228. {
  229. EvaluateUnaryI64(operation, (x) => (sbyte)x);
  230. }
  231. break;
  232. case Instruction.ZeroExtend16:
  233. if (type == OperandType.I32)
  234. {
  235. EvaluateUnaryI32(operation, (x) => (ushort)x);
  236. }
  237. else if (type == OperandType.I64)
  238. {
  239. EvaluateUnaryI64(operation, (x) => (ushort)x);
  240. }
  241. break;
  242. case Instruction.ZeroExtend32:
  243. if (type == OperandType.I32)
  244. {
  245. EvaluateUnaryI32(operation, (x) => x);
  246. }
  247. else if (type == OperandType.I64)
  248. {
  249. EvaluateUnaryI64(operation, (x) => (uint)x);
  250. }
  251. break;
  252. case Instruction.ZeroExtend8:
  253. if (type == OperandType.I32)
  254. {
  255. EvaluateUnaryI32(operation, (x) => (byte)x);
  256. }
  257. else if (type == OperandType.I64)
  258. {
  259. EvaluateUnaryI64(operation, (x) => (byte)x);
  260. }
  261. break;
  262. case Instruction.Subtract:
  263. if (type == OperandType.I32)
  264. {
  265. EvaluateBinaryI32(operation, (x, y) => x - y);
  266. }
  267. else if (type == OperandType.I64)
  268. {
  269. EvaluateBinaryI64(operation, (x, y) => x - y);
  270. }
  271. break;
  272. }
  273. }
  274. private static bool AreAllSourcesConstant(Operation operation)
  275. {
  276. for (int index = 0; index < operation.SourcesCount; index++)
  277. {
  278. Operand srcOp = operation.GetSource(index);
  279. if (srcOp.Kind != OperandKind.Constant)
  280. {
  281. return false;
  282. }
  283. }
  284. return true;
  285. }
  286. private static void EvaluateUnaryI32(Operation operation, Func<int, int> op)
  287. {
  288. int x = operation.GetSource(0).AsInt32();
  289. operation.TurnIntoCopy(Const(op(x)));
  290. }
  291. private static void EvaluateUnaryI64(Operation operation, Func<long, long> op)
  292. {
  293. long x = operation.GetSource(0).AsInt64();
  294. operation.TurnIntoCopy(Const(op(x)));
  295. }
  296. private static void EvaluateBinaryI32(Operation operation, Func<int, int, int> op)
  297. {
  298. int x = operation.GetSource(0).AsInt32();
  299. int y = operation.GetSource(1).AsInt32();
  300. operation.TurnIntoCopy(Const(op(x, y)));
  301. }
  302. private static void EvaluateBinaryI64(Operation operation, Func<long, long, long> op)
  303. {
  304. long x = operation.GetSource(0).AsInt64();
  305. long y = operation.GetSource(1).AsInt64();
  306. operation.TurnIntoCopy(Const(op(x, y)));
  307. }
  308. }
  309. }