Optimizer.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 (DestIsLocalVar(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 Span<Operation> GetUses(ref Span<Operation> buffer, Operand operand)
  83. {
  84. ReadOnlySpan<Operation> uses = operand.Uses;
  85. if (buffer.Length < uses.Length)
  86. {
  87. buffer = Allocators.Default.AllocateSpan<Operation>((uint)uses.Length);
  88. }
  89. uses.CopyTo(buffer);
  90. return buffer.Slice(0, uses.Length);
  91. }
  92. private static bool PropagateCompare(ref Span<Operation> buffer, Operation compOp)
  93. {
  94. // Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
  95. // of:
  96. //
  97. // - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x
  98. // - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x
  99. //
  100. // The commutative property of Equal and NotEqual is taken into consideration as well.
  101. //
  102. // For example:
  103. //
  104. // %x = Compare %a, %b, comp
  105. // BranchIf %x, 0x0, NotEqual
  106. //
  107. // =>
  108. //
  109. // BranchIf %a, %b, comp
  110. static bool IsZeroBranch(Operation operation, out Comparison compType)
  111. {
  112. compType = Comparison.Equal;
  113. if (operation.Instruction != Instruction.BranchIf)
  114. {
  115. return false;
  116. }
  117. Operand src1 = operation.GetSource(0);
  118. Operand src2 = operation.GetSource(1);
  119. Operand comp = operation.GetSource(2);
  120. compType = (Comparison)comp.AsInt32();
  121. return (src1.Kind == OperandKind.Constant && src1.Value == 0) ||
  122. (src2.Kind == OperandKind.Constant && src2.Value == 0);
  123. }
  124. bool modified = false;
  125. Operand dest = compOp.Destination;
  126. Operand src1 = compOp.GetSource(0);
  127. Operand src2 = compOp.GetSource(1);
  128. Operand comp = compOp.GetSource(2);
  129. Comparison compType = (Comparison)comp.AsInt32();
  130. Span<Operation> uses = GetUses(ref buffer, dest);
  131. foreach (Operation use in uses)
  132. {
  133. // If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands.
  134. if (IsZeroBranch(use, out Comparison otherCompType))
  135. {
  136. Comparison propCompType;
  137. if (otherCompType == Comparison.NotEqual)
  138. {
  139. propCompType = compType;
  140. }
  141. else if (otherCompType == Comparison.Equal)
  142. {
  143. propCompType = compType.Invert();
  144. }
  145. else
  146. {
  147. continue;
  148. }
  149. use.SetSource(0, src1);
  150. use.SetSource(1, src2);
  151. use.SetSource(2, Const((int)propCompType));
  152. modified = true;
  153. }
  154. }
  155. return modified;
  156. }
  157. private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
  158. {
  159. // Propagate copy source operand to all uses of the destination operand.
  160. Operand dest = copyOp.Destination;
  161. Operand source = copyOp.GetSource(0);
  162. Span<Operation> uses = GetUses(ref buffer, dest);
  163. foreach (Operation use in uses)
  164. {
  165. for (int index = 0; index < use.SourcesCount; index++)
  166. {
  167. if (use.GetSource(index) == dest)
  168. {
  169. use.SetSource(index, source);
  170. }
  171. }
  172. }
  173. }
  174. private static void RemoveNode(BasicBlock block, Operation node)
  175. {
  176. // Remove a node from the nodes list, and also remove itself
  177. // from all the use lists on the operands that this node uses.
  178. block.Operations.Remove(node);
  179. for (int index = 0; index < node.SourcesCount; index++)
  180. {
  181. node.SetSource(index, default);
  182. }
  183. Debug.Assert(node.Destination == default || node.Destination.UsesCount == 0);
  184. node.Destination = default;
  185. }
  186. private static bool IsUnused(Operation node)
  187. {
  188. return DestIsLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
  189. }
  190. private static bool DestIsLocalVar(Operation node)
  191. {
  192. return node.Destination != default && node.Destination.Kind == OperandKind.LocalVariable;
  193. }
  194. private static bool HasSideEffects(Operation node)
  195. {
  196. return node.Instruction == Instruction.Call
  197. || node.Instruction == Instruction.Tailcall
  198. || node.Instruction == Instruction.CompareAndSwap
  199. || node.Instruction == Instruction.CompareAndSwap16
  200. || node.Instruction == Instruction.CompareAndSwap8;
  201. }
  202. private static bool IsPropagableCompare(Operation operation)
  203. {
  204. return operation.Instruction == Instruction.Compare;
  205. }
  206. private static bool IsPropagableCopy(Operation operation)
  207. {
  208. if (operation.Instruction != Instruction.Copy)
  209. {
  210. return false;
  211. }
  212. return operation.Destination.Type == operation.GetSource(0).Type;
  213. }
  214. }
  215. }