InstEmitAluHelper.cs 6.3 KB

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