AstOptimizer.cs
1 using Ryujinx.Graphics.Shader.IntermediateRepresentation; 2 using Ryujinx.Graphics.Shader.Translation; 3 using System.Collections.Generic; 4 using System.Linq; 5 6 using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; 7 8 namespace Ryujinx.Graphics.Shader.StructuredIr 9 { 10 static class AstOptimizer 11 { 12 public static void Optimize(StructuredProgramContext context) 13 { 14 AstBlock mainBlock = context.CurrentFunction.MainBlock; 15 16 // When debug mode is enabled, we disable expression propagation 17 // (this makes comparison with the disassembly easier). 18 if (!context.DebugMode) 19 { 20 AstBlockVisitor visitor = new(mainBlock); 21 22 foreach (IAstNode node in visitor.Visit()) 23 { 24 if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar) 25 { 26 bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source); 27 28 if (propVar.Defs.Count == 1 && isWorthPropagating) 29 { 30 PropagateExpression(propVar, assignment.Source); 31 } 32 33 if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0) 34 { 35 visitor.Block.Remove(assignment); 36 37 context.CurrentFunction.Locals.Remove(propVar); 38 } 39 } 40 } 41 } 42 43 RemoveEmptyBlocks(mainBlock); 44 } 45 46 private static bool IsWorthPropagating(IAstNode source) 47 { 48 if (source is not AstOperation srcOp) 49 { 50 return false; 51 } 52 53 if (!InstructionInfo.IsUnary(srcOp.Inst)) 54 { 55 return false; 56 } 57 58 return srcOp.GetSource(0) is AstOperand || srcOp.Inst == Instruction.Copy; 59 } 60 61 private static void PropagateExpression(AstOperand propVar, IAstNode source) 62 { 63 IAstNode[] uses = propVar.Uses.ToArray(); 64 65 foreach (IAstNode useNode in uses) 66 { 67 if (useNode is AstBlock useBlock) 68 { 69 useBlock.Condition = source; 70 } 71 else if (useNode is AstOperation useOperation) 72 { 73 for (int srcIndex = 0; srcIndex < useOperation.SourcesCount; srcIndex++) 74 { 75 if (useOperation.GetSource(srcIndex) == propVar) 76 { 77 useOperation.SetSource(srcIndex, source); 78 } 79 } 80 } 81 else if (useNode is AstAssignment useAssignment) 82 { 83 useAssignment.Source = source; 84 } 85 } 86 } 87 88 private static void RemoveEmptyBlocks(AstBlock mainBlock) 89 { 90 Queue<AstBlock> pending = new(); 91 92 pending.Enqueue(mainBlock); 93 94 while (pending.TryDequeue(out AstBlock block)) 95 { 96 foreach (IAstNode node in block) 97 { 98 if (node is AstBlock childBlock) 99 { 100 pending.Enqueue(childBlock); 101 } 102 } 103 104 AstBlock parent = block.Parent; 105 106 if (parent == null) 107 { 108 continue; 109 } 110 111 AstBlock nextBlock = Next(block) as AstBlock; 112 113 bool hasElse = nextBlock != null && nextBlock.Type == AstBlockType.Else; 114 115 bool isIf = block.Type == AstBlockType.If; 116 117 if (block.Count == 0) 118 { 119 if (isIf) 120 { 121 if (hasElse) 122 { 123 nextBlock.TurnIntoIf(InverseCond(block.Condition)); 124 } 125 126 parent.Remove(block); 127 } 128 else if (block.Type == AstBlockType.Else) 129 { 130 parent.Remove(block); 131 } 132 } 133 else if (isIf && parent.Type == AstBlockType.Else && parent.Count == (hasElse ? 2 : 1)) 134 { 135 AstBlock parentOfParent = parent.Parent; 136 137 parent.Remove(block); 138 139 parentOfParent.AddAfter(parent, block); 140 141 if (hasElse) 142 { 143 parent.Remove(nextBlock); 144 145 parentOfParent.AddAfter(block, nextBlock); 146 } 147 148 parentOfParent.Remove(parent); 149 150 block.TurnIntoElseIf(); 151 } 152 } 153 } 154 } 155 }