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 }