/ src / Ryujinx.Graphics.Shader / Instructions / InstEmitAluHelper.cs
InstEmitAluHelper.cs
  1  using Ryujinx.Graphics.Shader.Decoders;
  2  using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3  using Ryujinx.Graphics.Shader.Translation;
  4  using System;
  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 class InstEmitAluHelper
 11      {
 12          public static long GetIntMin(IDstFmt type)
 13          {
 14              return type switch
 15              {
 16                  IDstFmt.U16 => ushort.MinValue,
 17                  IDstFmt.S16 => short.MinValue,
 18                  IDstFmt.U32 => uint.MinValue,
 19                  IDstFmt.S32 => int.MinValue,
 20                  _ => throw new ArgumentException($"The type \"{type}\" is not a supported integer type."),
 21              };
 22          }
 23  
 24          public static long GetIntMax(IDstFmt type)
 25          {
 26              return type switch
 27              {
 28                  IDstFmt.U16 => ushort.MaxValue,
 29                  IDstFmt.S16 => short.MaxValue,
 30                  IDstFmt.U32 => uint.MaxValue,
 31                  IDstFmt.S32 => int.MaxValue,
 32                  _ => throw new ArgumentException($"The type \"{type}\" is not a supported integer type."),
 33              };
 34          }
 35  
 36          public static long GetIntMin(ISrcDstFmt type)
 37          {
 38              return type switch
 39              {
 40                  ISrcDstFmt.U8 => byte.MinValue,
 41                  ISrcDstFmt.S8 => sbyte.MinValue,
 42                  ISrcDstFmt.U16 => ushort.MinValue,
 43                  ISrcDstFmt.S16 => short.MinValue,
 44                  ISrcDstFmt.U32 => uint.MinValue,
 45                  ISrcDstFmt.S32 => int.MinValue,
 46                  _ => throw new ArgumentException($"The type \"{type}\" is not a supported integer type."),
 47              };
 48          }
 49  
 50          public static long GetIntMax(ISrcDstFmt type)
 51          {
 52              return type switch
 53              {
 54                  ISrcDstFmt.U8 => byte.MaxValue,
 55                  ISrcDstFmt.S8 => sbyte.MaxValue,
 56                  ISrcDstFmt.U16 => ushort.MaxValue,
 57                  ISrcDstFmt.S16 => short.MaxValue,
 58                  ISrcDstFmt.U32 => uint.MaxValue,
 59                  ISrcDstFmt.S32 => int.MaxValue,
 60                  _ => throw new ArgumentException($"The type \"{type}\" is not a supported integer type."),
 61              };
 62          }
 63  
 64          public static Operand GetPredLogicalOp(EmitterContext context, BoolOp logicOp, Operand input, Operand pred)
 65          {
 66              return logicOp switch
 67              {
 68                  BoolOp.And => context.BitwiseAnd(input, pred),
 69                  BoolOp.Or => context.BitwiseOr(input, pred),
 70                  BoolOp.Xor => context.BitwiseExclusiveOr(input, pred),
 71                  _ => input,
 72              };
 73          }
 74  
 75          public static Operand Extend(EmitterContext context, Operand src, VectorSelect type)
 76          {
 77              return type switch
 78              {
 79                  VectorSelect.U8B0 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(0)), 8),
 80                  VectorSelect.U8B1 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(8)), 8),
 81                  VectorSelect.U8B2 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(16)), 8),
 82                  VectorSelect.U8B3 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(24)), 8),
 83                  VectorSelect.U16H0 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(0)), 16),
 84                  VectorSelect.U16H1 => ZeroExtendTo32(context, context.ShiftRightU32(src, Const(16)), 16),
 85                  VectorSelect.S8B0 => SignExtendTo32(context, context.ShiftRightU32(src, Const(0)), 8),
 86                  VectorSelect.S8B1 => SignExtendTo32(context, context.ShiftRightU32(src, Const(8)), 8),
 87                  VectorSelect.S8B2 => SignExtendTo32(context, context.ShiftRightU32(src, Const(16)), 8),
 88                  VectorSelect.S8B3 => SignExtendTo32(context, context.ShiftRightU32(src, Const(24)), 8),
 89                  VectorSelect.S16H0 => SignExtendTo32(context, context.ShiftRightU32(src, Const(0)), 16),
 90                  VectorSelect.S16H1 => SignExtendTo32(context, context.ShiftRightU32(src, Const(16)), 16),
 91                  _ => src,
 92              };
 93          }
 94  
 95          public static void SetZnFlags(EmitterContext context, Operand dest, bool setCC, bool extended = false)
 96          {
 97              if (!setCC)
 98              {
 99                  return;
100              }
101  
102              if (extended)
103              {
104                  // When the operation is extended, it means we are doing
105                  // the operation on a long word with any number of bits,
106                  // so we need to AND the zero flag from result with the
107                  // previous result when extended is specified, to ensure
108                  // we have ZF set only if all words are zero, and not just
109                  // the last one.
110                  Operand oldZF = GetZF();
111  
112                  Operand res = context.BitwiseAnd(context.ICompareEqual(dest, Const(0)), oldZF);
113  
114                  context.Copy(GetZF(), res);
115              }
116              else
117              {
118                  context.Copy(GetZF(), context.ICompareEqual(dest, Const(0)));
119              }
120  
121              context.Copy(GetNF(), context.ICompareLess(dest, Const(0)));
122          }
123  
124          public static void SetFPZnFlags(EmitterContext context, Operand dest, bool setCC, Instruction fpType = Instruction.FP32)
125          {
126              if (setCC)
127              {
128                  Operand zero = ConstF(0);
129  
130                  if (fpType == Instruction.FP64)
131                  {
132                      zero = context.FP32ConvertToFP64(zero);
133                  }
134  
135                  context.Copy(GetZF(), context.FPCompareEqual(dest, zero, fpType));
136                  context.Copy(GetNF(), context.FPCompareLess(dest, zero, fpType));
137              }
138          }
139  
140          public static (Operand, Operand) NegateLong(EmitterContext context, Operand low, Operand high)
141          {
142              low = context.BitwiseNot(low);
143              high = context.BitwiseNot(high);
144              low = AddWithCarry(context, low, Const(1), out Operand carryOut);
145              high = context.IAdd(high, carryOut);
146              return (low, high);
147          }
148  
149          public static Operand AddWithCarry(EmitterContext context, Operand lhs, Operand rhs, out Operand carryOut)
150          {
151              Operand result = context.IAdd(lhs, rhs);
152  
153              // C = Rd < Rn
154              carryOut = context.INegate(context.ICompareLessUnsigned(result, lhs));
155  
156              return result;
157          }
158      }
159  }