Simplification.cs
1 using Ryujinx.Graphics.Shader.IntermediateRepresentation; 2 3 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; 4 5 namespace Ryujinx.Graphics.Shader.Translation.Optimizations 6 { 7 static class Simplification 8 { 9 private const int AllOnes = ~0; 10 11 public static void RunPass(Operation operation) 12 { 13 switch (operation.Inst) 14 { 15 case Instruction.Add: 16 TryEliminateBinaryOpCommutative(operation, 0); 17 break; 18 19 case Instruction.BitwiseAnd: 20 TryEliminateBitwiseAnd(operation); 21 break; 22 23 case Instruction.BitwiseExclusiveOr: 24 if (!TryEliminateXorSwap(operation)) 25 { 26 TryEliminateBinaryOpCommutative(operation, 0); 27 } 28 break; 29 30 case Instruction.BitwiseOr: 31 TryEliminateBitwiseOr(operation); 32 break; 33 34 case Instruction.CompareNotEqual: 35 TryEliminateCompareNotEqual(operation); 36 break; 37 38 case Instruction.ConditionalSelect: 39 TryEliminateConditionalSelect(operation); 40 break; 41 42 case Instruction.Divide: 43 TryEliminateBinaryOpY(operation, 1); 44 break; 45 46 case Instruction.Multiply: 47 TryEliminateBinaryOpCommutative(operation, 1); 48 break; 49 50 case Instruction.ShiftLeft: 51 case Instruction.ShiftRightS32: 52 case Instruction.ShiftRightU32: 53 case Instruction.Subtract: 54 TryEliminateBinaryOpY(operation, 0); 55 break; 56 } 57 } 58 59 private static void TryEliminateBitwiseAnd(Operation operation) 60 { 61 // Try to recognize and optimize those 3 patterns (in order): 62 // x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y, 63 // x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000 64 65 Operand x = operation.GetSource(0); 66 Operand y = operation.GetSource(1); 67 68 if (IsConstEqual(x, AllOnes)) 69 { 70 operation.TurnIntoCopy(y); 71 } 72 else if (IsConstEqual(y, AllOnes)) 73 { 74 operation.TurnIntoCopy(x); 75 } 76 else if (IsConstEqual(x, 0) || IsConstEqual(y, 0)) 77 { 78 operation.TurnIntoCopy(Const(0)); 79 } 80 } 81 82 private static bool TryEliminateXorSwap(Operation xCopyOp) 83 { 84 // Try to recognize XOR swap pattern: 85 // x = x ^ y 86 // y = x ^ y 87 // x = x ^ y 88 // Or, in SSA: 89 // x2 = x ^ y 90 // y2 = x2 ^ y 91 // x3 = x2 ^ y2 92 // Transform it into something more sane: 93 // temp = y 94 // y = x 95 // x = temp 96 97 // Note that because XOR is commutative, there are actually 98 // multiple possible combinations of this pattern, for 99 // simplicity this only catches one of them. 100 101 Operand x = xCopyOp.GetSource(0); 102 Operand y = xCopyOp.GetSource(1); 103 104 if (x.AsgOp is not Operation tCopyOp || tCopyOp.Inst != Instruction.BitwiseExclusiveOr || 105 y.AsgOp is not Operation yCopyOp || yCopyOp.Inst != Instruction.BitwiseExclusiveOr) 106 { 107 return false; 108 } 109 110 if (tCopyOp == yCopyOp) 111 { 112 return false; 113 } 114 115 if (yCopyOp.GetSource(0) != x || 116 yCopyOp.GetSource(1) != tCopyOp.GetSource(1) || 117 x.UseOps.Count != 2) 118 { 119 return false; 120 } 121 122 x = tCopyOp.GetSource(0); 123 y = tCopyOp.GetSource(1); 124 125 tCopyOp.TurnIntoCopy(y); // Temp = Y 126 yCopyOp.TurnIntoCopy(x); // Y = X 127 xCopyOp.TurnIntoCopy(tCopyOp.Dest); // X = Temp 128 129 return true; 130 } 131 132 private static void TryEliminateBitwiseOr(Operation operation) 133 { 134 // Try to recognize and optimize those 3 patterns (in order): 135 // x | 0x00000000 == x, 0x00000000 | y == y, 136 // x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF 137 138 Operand x = operation.GetSource(0); 139 Operand y = operation.GetSource(1); 140 141 if (IsConstEqual(x, 0)) 142 { 143 operation.TurnIntoCopy(y); 144 } 145 else if (IsConstEqual(y, 0)) 146 { 147 operation.TurnIntoCopy(x); 148 } 149 else if (IsConstEqual(x, AllOnes) || IsConstEqual(y, AllOnes)) 150 { 151 operation.TurnIntoCopy(Const(AllOnes)); 152 } 153 } 154 155 private static void TryEliminateBinaryOpY(Operation operation, int comparand) 156 { 157 Operand x = operation.GetSource(0); 158 Operand y = operation.GetSource(1); 159 160 if (IsConstEqual(y, comparand)) 161 { 162 operation.TurnIntoCopy(x); 163 } 164 } 165 166 private static void TryEliminateBinaryOpCommutative(Operation operation, int comparand) 167 { 168 Operand x = operation.GetSource(0); 169 Operand y = operation.GetSource(1); 170 171 if (IsConstEqual(x, comparand)) 172 { 173 operation.TurnIntoCopy(y); 174 } 175 else if (IsConstEqual(y, comparand)) 176 { 177 operation.TurnIntoCopy(x); 178 } 179 } 180 181 private static void TryEliminateCompareNotEqual(Operation operation) 182 { 183 // Comparison instruction returns 0 if the result is false, and -1 if true. 184 // Doing a not equal zero comparison on the result is redundant, so we can just copy the first result in this case. 185 186 Operand lhs = operation.GetSource(0); 187 Operand rhs = operation.GetSource(1); 188 189 if (lhs.Type == OperandType.Constant) 190 { 191 (lhs, rhs) = (rhs, lhs); 192 } 193 194 if (rhs.Type != OperandType.Constant || rhs.Value != 0) 195 { 196 return; 197 } 198 199 if (lhs.AsgOp is not Operation compareOp || !compareOp.Inst.IsComparison()) 200 { 201 return; 202 } 203 204 operation.TurnIntoCopy(lhs); 205 } 206 207 private static void TryEliminateConditionalSelect(Operation operation) 208 { 209 Operand cond = operation.GetSource(0); 210 211 if (cond.Type != OperandType.Constant) 212 { 213 return; 214 } 215 216 // The condition is constant, we can turn it into a copy, and select 217 // the source based on the condition value. 218 int srcIndex = cond.Value != 0 ? 1 : 2; 219 220 Operand source = operation.GetSource(srcIndex); 221 222 operation.TurnIntoCopy(source); 223 } 224 225 private static bool IsConstEqual(Operand operand, int comparand) 226 { 227 if (operand.Type != OperandType.Constant) 228 { 229 return false; 230 } 231 232 return operand.Value == comparand; 233 } 234 } 235 }