Optimizer.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. namespace Ryujinx.Graphics.Shader.Translation.Optimizations
  6. {
  7. static class Optimizer
  8. {
  9. public static void Optimize(BasicBlock[] blocks, ShaderStage stage)
  10. {
  11. for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
  12. {
  13. GlobalToStorage.RunPass(blocks[blkIndex], stage);
  14. }
  15. bool modified;
  16. do
  17. {
  18. modified = false;
  19. for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
  20. {
  21. BasicBlock block = blocks[blkIndex];
  22. LinkedListNode<INode> node = block.Operations.First;
  23. while (node != null)
  24. {
  25. LinkedListNode<INode> nextNode = node.Next;
  26. bool isUnused = IsUnused(node.Value);
  27. if (!(node.Value is Operation operation) || isUnused)
  28. {
  29. if (isUnused)
  30. {
  31. RemoveNode(block, node);
  32. modified = true;
  33. }
  34. node = nextNode;
  35. continue;
  36. }
  37. ConstantFolding.RunPass(operation);
  38. Simplification.RunPass(operation);
  39. if (DestIsLocalVar(operation))
  40. {
  41. if (operation.Inst == Instruction.Copy)
  42. {
  43. PropagateCopy(operation);
  44. RemoveNode(block, node);
  45. modified = true;
  46. }
  47. else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) ||
  48. (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation)))
  49. {
  50. if (operation.Dest.UseOps.Count == 0)
  51. {
  52. RemoveNode(block, node);
  53. }
  54. modified = true;
  55. }
  56. }
  57. node = nextNode;
  58. }
  59. if (BranchElimination.RunPass(block))
  60. {
  61. RemoveNode(block, block.Operations.Last);
  62. modified = true;
  63. }
  64. }
  65. }
  66. while (modified);
  67. }
  68. private static void PropagateCopy(Operation copyOp)
  69. {
  70. // Propagate copy source operand to all uses of
  71. // the destination operand.
  72. Operand dest = copyOp.Dest;
  73. Operand src = copyOp.GetSource(0);
  74. INode[] uses = dest.UseOps.ToArray();
  75. foreach (INode useNode in uses)
  76. {
  77. for (int index = 0; index < useNode.SourcesCount; index++)
  78. {
  79. if (useNode.GetSource(index) == dest)
  80. {
  81. useNode.SetSource(index, src);
  82. }
  83. }
  84. }
  85. }
  86. private static bool PropagatePack(Operation packOp)
  87. {
  88. // Propagate pack source operands to uses by unpack
  89. // instruction. The source depends on the unpack instruction.
  90. bool modified = false;
  91. Operand dest = packOp.Dest;
  92. Operand src0 = packOp.GetSource(0);
  93. Operand src1 = packOp.GetSource(1);
  94. INode[] uses = dest.UseOps.ToArray();
  95. foreach (INode useNode in uses)
  96. {
  97. if (!(useNode is Operation operation) || operation.Inst != Instruction.UnpackHalf2x16)
  98. {
  99. continue;
  100. }
  101. if (operation.GetSource(0) == dest)
  102. {
  103. operation.TurnIntoCopy(operation.ComponentIndex == 1 ? src1 : src0);
  104. modified = true;
  105. }
  106. }
  107. return modified;
  108. }
  109. public static bool MatchDdxOrDdy(Operation operation)
  110. {
  111. // It's assumed that "operation.Inst" is ShuffleXor,
  112. // that should be checked before calling this method.
  113. Debug.Assert(operation.Inst == Instruction.ShuffleXor);
  114. bool modified = false;
  115. Operand src2 = operation.GetSource(1);
  116. Operand src3 = operation.GetSource(2);
  117. if (src2.Type != OperandType.Constant || (src2.Value != 1 && src2.Value != 2))
  118. {
  119. return false;
  120. }
  121. if (src3.Type != OperandType.Constant || src3.Value != 0x1c03)
  122. {
  123. return false;
  124. }
  125. bool isDdy = src2.Value == 2;
  126. bool isDdx = !isDdy;
  127. // We can replace any use by a FSWZADD with DDX/DDY, when
  128. // the following conditions are true:
  129. // - The mask should be 0b10100101 for DDY, or 0b10011001 for DDX.
  130. // - The first source operand must be the shuffle output.
  131. // - The second source operand must be the shuffle first source operand.
  132. INode[] uses = operation.Dest.UseOps.ToArray();
  133. foreach (INode use in uses)
  134. {
  135. if (!(use is Operation test))
  136. {
  137. continue;
  138. }
  139. if (!(use is Operation useOp) || useOp.Inst != Instruction.SwizzleAdd)
  140. {
  141. continue;
  142. }
  143. Operand fswzaddSrc1 = useOp.GetSource(0);
  144. Operand fswzaddSrc2 = useOp.GetSource(1);
  145. Operand fswzaddSrc3 = useOp.GetSource(2);
  146. if (fswzaddSrc1 != operation.Dest)
  147. {
  148. continue;
  149. }
  150. if (fswzaddSrc2 != operation.GetSource(0))
  151. {
  152. continue;
  153. }
  154. if (fswzaddSrc3.Type != OperandType.Constant)
  155. {
  156. continue;
  157. }
  158. int mask = fswzaddSrc3.Value;
  159. if ((isDdx && mask != 0b10011001) ||
  160. (isDdy && mask != 0b10100101))
  161. {
  162. continue;
  163. }
  164. useOp.TurnInto(isDdx ? Instruction.Ddx : Instruction.Ddy, fswzaddSrc2);
  165. modified = true;
  166. }
  167. return modified;
  168. }
  169. private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
  170. {
  171. // Remove a node from the nodes list, and also remove itself
  172. // from all the use lists on the operands that this node uses.
  173. block.Operations.Remove(llNode);
  174. Queue<INode> nodes = new Queue<INode>();
  175. nodes.Enqueue(llNode.Value);
  176. while (nodes.TryDequeue(out INode node))
  177. {
  178. for (int index = 0; index < node.SourcesCount; index++)
  179. {
  180. Operand src = node.GetSource(index);
  181. if (src.Type != OperandType.LocalVariable)
  182. {
  183. continue;
  184. }
  185. if (src.UseOps.Remove(node) && src.UseOps.Count == 0)
  186. {
  187. nodes.Enqueue(src.AsgOp);
  188. }
  189. }
  190. }
  191. }
  192. private static bool IsUnused(INode node)
  193. {
  194. return DestIsLocalVar(node) && node.Dest.UseOps.Count == 0;
  195. }
  196. private static bool DestIsLocalVar(INode node)
  197. {
  198. return node.Dest != null && node.Dest.Type == OperandType.LocalVariable;
  199. }
  200. }
  201. }