/ src / Ryujinx.Graphics.Shader / Instructions / InstEmitShift.cs
InstEmitShift.cs
  1  using Ryujinx.Graphics.Shader.Decoders;
  2  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3  using Ryujinx.Graphics.Shader.Translation;
  4  
  5  using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  6  using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7  
  8  namespace Ryujinx.Graphics.Shader.Instructions
  9  {
 10      static partial class InstEmit
 11      {
 12          public static void ShfLR(EmitterContext context)
 13          {
 14              InstShfLR op = context.GetOp<InstShfLR>();
 15  
 16              var srcA = GetSrcReg(context, op.SrcA);
 17              var srcB = GetSrcReg(context, op.SrcB);
 18              var srcC = GetSrcReg(context, op.SrcC);
 19  
 20              EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
 21          }
 22  
 23          public static void ShfRR(EmitterContext context)
 24          {
 25              InstShfRR op = context.GetOp<InstShfRR>();
 26  
 27              var srcA = GetSrcReg(context, op.SrcA);
 28              var srcB = GetSrcReg(context, op.SrcB);
 29              var srcC = GetSrcReg(context, op.SrcC);
 30  
 31              EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
 32          }
 33  
 34          public static void ShfLI(EmitterContext context)
 35          {
 36              InstShfLI op = context.GetOp<InstShfLI>();
 37  
 38              var srcA = GetSrcReg(context, op.SrcA);
 39              var srcB = Const(op.Imm6);
 40              var srcC = GetSrcReg(context, op.SrcC);
 41  
 42              EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
 43          }
 44  
 45          public static void ShfRI(EmitterContext context)
 46          {
 47              InstShfRI op = context.GetOp<InstShfRI>();
 48  
 49              var srcA = GetSrcReg(context, op.SrcA);
 50              var srcB = Const(op.Imm6);
 51              var srcC = GetSrcReg(context, op.SrcC);
 52  
 53              EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
 54          }
 55  
 56          public static void ShlR(EmitterContext context)
 57          {
 58              InstShlR op = context.GetOp<InstShlR>();
 59  
 60              EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcReg(context, op.SrcB), op.Dest, op.M);
 61          }
 62  
 63          public static void ShlI(EmitterContext context)
 64          {
 65              InstShlI op = context.GetOp<InstShlI>();
 66  
 67              EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcImm(context, Imm20ToSInt(op.Imm20)), op.Dest, op.M);
 68          }
 69  
 70          public static void ShlC(EmitterContext context)
 71          {
 72              InstShlC op = context.GetOp<InstShlC>();
 73  
 74              EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcCbuf(context, op.CbufSlot, op.CbufOffset), op.Dest, op.M);
 75          }
 76  
 77          public static void ShrR(EmitterContext context)
 78          {
 79              InstShrR op = context.GetOp<InstShrR>();
 80  
 81              var srcA = GetSrcReg(context, op.SrcA);
 82              var srcB = GetSrcReg(context, op.SrcB);
 83  
 84              EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
 85          }
 86  
 87          public static void ShrI(EmitterContext context)
 88          {
 89              InstShrI op = context.GetOp<InstShrI>();
 90  
 91              var srcA = GetSrcReg(context, op.SrcA);
 92              var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
 93  
 94              EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
 95          }
 96  
 97          public static void ShrC(EmitterContext context)
 98          {
 99              InstShrC op = context.GetOp<InstShrC>();
100  
101              var srcA = GetSrcReg(context, op.SrcA);
102              var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
103  
104              EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
105          }
106  
107          private static void EmitShf(
108              EmitterContext context,
109              MaxShift maxShift,
110              Operand srcA,
111              Operand srcB,
112              Operand srcC,
113              int rd,
114              bool mask,
115              bool left,
116              bool writeCC)
117          {
118              bool isLongShift = maxShift == MaxShift.U64 || maxShift == MaxShift.S64;
119              bool signedShift = maxShift == MaxShift.S64;
120              int maxShiftConst = isLongShift ? 64 : 32;
121  
122              if (mask)
123              {
124                  srcB = context.BitwiseAnd(srcB, Const(maxShiftConst - 1));
125              }
126  
127              Operand res;
128  
129              if (left)
130              {
131                  // res = (C << B) | (A >> (32 - B))
132                  res = context.ShiftLeft(srcC, srcB);
133                  res = context.BitwiseOr(res, context.ShiftRightU32(srcA, context.ISubtract(Const(32), srcB)));
134  
135                  if (isLongShift)
136                  {
137                      // res = B >= 32 ? A << (B - 32) : res
138                      Operand lowerShift = context.ShiftLeft(srcA, context.ISubtract(srcB, Const(32)));
139  
140                      Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
141                      res = context.ConditionalSelect(shiftGreaterThan31, lowerShift, res);
142                  }
143              }
144              else
145              {
146                  // res = (A >> B) | (C << (32 - B))
147                  res = context.ShiftRightU32(srcA, srcB);
148                  res = context.BitwiseOr(res, context.ShiftLeft(srcC, context.ISubtract(Const(32), srcB)));
149  
150                  if (isLongShift)
151                  {
152                      // res = B >= 32 ? C >> (B - 32) : res
153                      Operand upperShift = signedShift
154                          ? context.ShiftRightS32(srcC, context.ISubtract(srcB, Const(32)))
155                          : context.ShiftRightU32(srcC, context.ISubtract(srcB, Const(32)));
156  
157                      Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
158                      res = context.ConditionalSelect(shiftGreaterThan31, upperShift, res);
159                  }
160              }
161  
162              if (!mask)
163              {
164                  // Clamped shift value.
165                  Operand isLessThanMax = context.ICompareLessUnsigned(srcB, Const(maxShiftConst));
166  
167                  res = context.ConditionalSelect(isLessThanMax, res, Const(0));
168              }
169  
170              context.Copy(GetDest(rd), res);
171  
172              if (writeCC)
173              {
174                  InstEmitAluHelper.SetZnFlags(context, res, writeCC);
175              }
176  
177              // TODO: X.
178          }
179  
180          private static void EmitShl(EmitterContext context, Operand srcA, Operand srcB, int rd, bool mask)
181          {
182              if (mask)
183              {
184                  srcB = context.BitwiseAnd(srcB, Const(0x1f));
185              }
186  
187              Operand res = context.ShiftLeft(srcA, srcB);
188  
189              if (!mask)
190              {
191                  // Clamped shift value.
192                  Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
193  
194                  res = context.ConditionalSelect(isLessThan32, res, Const(0));
195              }
196  
197              // TODO: X, CC.
198  
199              context.Copy(GetDest(rd), res);
200          }
201  
202          private static void EmitShr(
203              EmitterContext context,
204              Operand srcA,
205              Operand srcB,
206              int rd,
207              bool mask,
208              bool bitReverse,
209              bool isSigned)
210          {
211              if (bitReverse)
212              {
213                  srcA = context.BitfieldReverse(srcA);
214              }
215  
216              if (mask)
217              {
218                  srcB = context.BitwiseAnd(srcB, Const(0x1f));
219              }
220  
221              Operand res = isSigned
222                  ? context.ShiftRightS32(srcA, srcB)
223                  : context.ShiftRightU32(srcA, srcB);
224  
225              if (!mask)
226              {
227                  // Clamped shift value.
228                  Operand resShiftBy32;
229  
230                  if (isSigned)
231                  {
232                      resShiftBy32 = context.ShiftRightS32(srcA, Const(31));
233                  }
234                  else
235                  {
236                      resShiftBy32 = Const(0);
237                  }
238  
239                  Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
240  
241                  res = context.ConditionalSelect(isLessThan32, res, resShiftBy32);
242              }
243  
244              // TODO: X, CC.
245  
246              context.Copy(GetDest(rd), res);
247          }
248      }
249  }