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  }