AstOptimizer.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper;
  5. namespace Ryujinx.Graphics.Shader.StructuredIr
  6. {
  7. static class AstOptimizer
  8. {
  9. public static void Optimize(StructuredProgramInfo info)
  10. {
  11. AstBlock mainBlock = info.MainBlock;
  12. AstBlockVisitor visitor = new AstBlockVisitor(mainBlock);
  13. foreach (IAstNode node in visitor.Visit())
  14. {
  15. if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar)
  16. {
  17. bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source);
  18. if (propVar.Defs.Count == 1 && isWorthPropagating)
  19. {
  20. PropagateExpression(propVar, assignment.Source);
  21. }
  22. if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0)
  23. {
  24. visitor.Block.Remove(assignment);
  25. info.Locals.Remove(propVar);
  26. }
  27. }
  28. }
  29. RemoveEmptyBlocks(mainBlock);
  30. }
  31. private static bool IsWorthPropagating(IAstNode source)
  32. {
  33. if (!(source is AstOperation srcOp))
  34. {
  35. return false;
  36. }
  37. if (!InstructionInfo.IsUnary(srcOp.Inst))
  38. {
  39. return false;
  40. }
  41. return srcOp.GetSource(0) is AstOperand || srcOp.Inst == Instruction.Copy;
  42. }
  43. private static void PropagateExpression(AstOperand propVar, IAstNode source)
  44. {
  45. IAstNode[] uses = propVar.Uses.ToArray();
  46. foreach (IAstNode useNode in uses)
  47. {
  48. if (useNode is AstBlock useBlock)
  49. {
  50. useBlock.Condition = source;
  51. }
  52. else if (useNode is AstOperation useOperation)
  53. {
  54. for (int srcIndex = 0; srcIndex < useOperation.SourcesCount; srcIndex++)
  55. {
  56. if (useOperation.GetSource(srcIndex) == propVar)
  57. {
  58. useOperation.SetSource(srcIndex, source);
  59. }
  60. }
  61. }
  62. else if (useNode is AstAssignment useAssignment)
  63. {
  64. useAssignment.Source = source;
  65. }
  66. }
  67. }
  68. private static void RemoveEmptyBlocks(AstBlock mainBlock)
  69. {
  70. Queue<AstBlock> pending = new Queue<AstBlock>();
  71. pending.Enqueue(mainBlock);
  72. while (pending.TryDequeue(out AstBlock block))
  73. {
  74. foreach (IAstNode node in block)
  75. {
  76. if (node is AstBlock childBlock)
  77. {
  78. pending.Enqueue(childBlock);
  79. }
  80. }
  81. AstBlock parent = block.Parent;
  82. if (parent == null)
  83. {
  84. continue;
  85. }
  86. AstBlock nextBlock = Next(block) as AstBlock;
  87. bool hasElse = nextBlock != null && nextBlock.Type == AstBlockType.Else;
  88. bool isIf = block.Type == AstBlockType.If;
  89. if (block.Count == 0)
  90. {
  91. if (isIf)
  92. {
  93. if (hasElse)
  94. {
  95. nextBlock.TurnIntoIf(InverseCond(block.Condition));
  96. }
  97. parent.Remove(block);
  98. }
  99. else if (block.Type == AstBlockType.Else)
  100. {
  101. parent.Remove(block);
  102. }
  103. }
  104. else if (isIf && parent.Type == AstBlockType.Else && parent.Count == (hasElse ? 2 : 1))
  105. {
  106. AstBlock parentOfParent = parent.Parent;
  107. parent.Remove(block);
  108. parentOfParent.AddAfter(parent, block);
  109. if (hasElse)
  110. {
  111. parent.Remove(nextBlock);
  112. parentOfParent.AddAfter(block, nextBlock);
  113. }
  114. parentOfParent.Remove(parent);
  115. block.TurnIntoElseIf();
  116. }
  117. }
  118. }
  119. }
  120. }