Optimizer.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using ARMeilleure.IntermediateRepresentation;
  2. using ARMeilleure.Translation;
  3. using System;
  4. using System.Diagnostics;
  5. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  6. namespace ARMeilleure.CodeGen.Optimizations
  7. {
  8. static class Optimizer
  9. {
  10. public static void RunPass(ControlFlowGraph cfg)
  11. {
  12. // Scratch buffer used to store uses.
  13. Span<Operation> buffer = default;
  14. bool modified;
  15. do
  16. {
  17. modified = false;
  18. for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
  19. {
  20. Operation node;
  21. Operation prevNode;
  22. for (node = block.Operations.Last; node != default; node = prevNode)
  23. {
  24. prevNode = node.ListPrevious;
  25. if (IsUnused(node))
  26. {
  27. RemoveNode(block, node);
  28. modified = true;
  29. continue;
  30. }
  31. else if (node.Instruction == Instruction.Phi)
  32. {
  33. continue;
  34. }
  35. ConstantFolding.RunPass(node);
  36. Simplification.RunPass(node);
  37. if (DestIsSingleLocalVar(node))
  38. {
  39. if (IsPropagableCompare(node))
  40. {
  41. modified |= PropagateCompare(ref buffer, node);
  42. if (modified && IsUnused(node))
  43. {
  44. RemoveNode(block, node);
  45. }
  46. }
  47. else if (IsPropagableCopy(node))
  48. {
  49. PropagateCopy(ref buffer, node);
  50. RemoveNode(block, node);
  51. modified = true;
  52. }
  53. }
  54. }
  55. }
  56. }
  57. while (modified);
  58. }
  59. public static void RemoveUnusedNodes(ControlFlowGraph cfg)
  60. {
  61. bool modified;
  62. do
  63. {
  64. modified = false;
  65. for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
  66. {
  67. Operation node;
  68. Operation prevNode;
  69. for (node = block.Operations.Last; node != default; node = prevNode)
  70. {
  71. prevNode = node.ListPrevious;
  72. if (IsUnused(node))
  73. {
  74. RemoveNode(block, node);
  75. modified = true;
  76. }
  77. }
  78. }
  79. }
  80. while (modified);
  81. }
  82. private static bool PropagateCompare(ref Span<Operation> buffer, Operation compOp)
  83. {
  84. // Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
  85. // of:
  86. //
  87. // - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x
  88. // - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x
  89. //
  90. // The commutative property of Equal and NotEqual is taken into consideration as well.
  91. //
  92. // For example:
  93. //
  94. // %x = Compare %a, %b, comp
  95. // BranchIf %x, 0x0, NotEqual
  96. //
  97. // =>
  98. //
  99. // BranchIf %a, %b, comp
  100. static bool IsZeroBranch(Operation operation, out Comparison compType)
  101. {
  102. compType = Comparison.Equal;
  103. if (operation.Instruction != Instruction.BranchIf)
  104. {
  105. return false;
  106. }
  107. Operand src1 = operation.GetSource(0);
  108. Operand src2 = operation.GetSource(1);
  109. Operand comp = operation.GetSource(2);
  110. compType = (Comparison)comp.AsInt32();
  111. return (src1.Kind == OperandKind.Constant && src1.Value == 0) ||
  112. (src2.Kind == OperandKind.Constant && src2.Value == 0);
  113. }
  114. bool modified = false;
  115. Operand dest = compOp.Destination;
  116. Operand src1 = compOp.GetSource(0);
  117. Operand src2 = compOp.GetSource(1);
  118. Operand comp = compOp.GetSource(2);
  119. Comparison compType = (Comparison)comp.AsInt32();
  120. Span<Operation> uses = dest.GetUses(ref buffer);
  121. foreach (Operation use in uses)
  122. {
  123. // If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands.
  124. if (IsZeroBranch(use, out Comparison otherCompType))
  125. {
  126. Comparison propCompType;
  127. if (otherCompType == Comparison.NotEqual)
  128. {
  129. propCompType = compType;
  130. }
  131. else if (otherCompType == Comparison.Equal)
  132. {
  133. propCompType = compType.Invert();
  134. }
  135. else
  136. {
  137. continue;
  138. }
  139. use.SetSource(0, src1);
  140. use.SetSource(1, src2);
  141. use.SetSource(2, Const((int)propCompType));
  142. modified = true;
  143. }
  144. }
  145. return modified;
  146. }
  147. private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
  148. {
  149. // Propagate copy source operand to all uses of the destination operand.
  150. Operand dest = copyOp.Destination;
  151. Operand source = copyOp.GetSource(0);
  152. Span<Operation> uses = dest.GetUses(ref buffer);
  153. foreach (Operation use in uses)
  154. {
  155. for (int index = 0; index < use.SourcesCount; index++)
  156. {
  157. if (use.GetSource(index) == dest)
  158. {
  159. use.SetSource(index, source);
  160. }
  161. }
  162. }
  163. }
  164. private static void RemoveNode(BasicBlock block, Operation node)
  165. {
  166. // Remove a node from the nodes list, and also remove itself
  167. // from all the use lists on the operands that this node uses.
  168. block.Operations.Remove(node);
  169. for (int index = 0; index < node.SourcesCount; index++)
  170. {
  171. node.SetSource(index, default);
  172. }
  173. Debug.Assert(node.Destination == default || node.Destination.UsesCount == 0);
  174. node.Destination = default;
  175. }
  176. private static bool IsUnused(Operation node)
  177. {
  178. return DestIsSingleLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
  179. }
  180. private static bool DestIsSingleLocalVar(Operation node)
  181. {
  182. return node.DestinationsCount == 1 && node.Destination.Kind == OperandKind.LocalVariable;
  183. }
  184. private static bool HasSideEffects(Operation node)
  185. {
  186. return node.Instruction == Instruction.Call
  187. || node.Instruction == Instruction.Tailcall
  188. || node.Instruction == Instruction.CompareAndSwap
  189. || node.Instruction == Instruction.CompareAndSwap16
  190. || node.Instruction == Instruction.CompareAndSwap8;
  191. }
  192. private static bool IsPropagableCompare(Operation operation)
  193. {
  194. return operation.Instruction == Instruction.Compare;
  195. }
  196. private static bool IsPropagableCopy(Operation operation)
  197. {
  198. if (operation.Instruction != Instruction.Copy)
  199. {
  200. return false;
  201. }
  202. return operation.Destination.Type == operation.GetSource(0).Type;
  203. }
  204. }
  205. }