InstEmitIntegerComparison.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.InstEmitAluHelper; 6 using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; 7 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; 8 9 namespace Ryujinx.Graphics.Shader.Instructions 10 { 11 static partial class InstEmit 12 { 13 public static void IcmpR(EmitterContext context) 14 { 15 InstIcmpR op = context.GetOp<InstIcmpR>(); 16 17 var srcA = GetSrcReg(context, op.SrcA); 18 var srcB = GetSrcReg(context, op.SrcB); 19 var srcC = GetSrcReg(context, op.SrcC); 20 21 EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); 22 } 23 24 public static void IcmpI(EmitterContext context) 25 { 26 InstIcmpI op = context.GetOp<InstIcmpI>(); 27 28 var srcA = GetSrcReg(context, op.SrcA); 29 var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); 30 var srcC = GetSrcReg(context, op.SrcC); 31 32 EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); 33 } 34 35 public static void IcmpC(EmitterContext context) 36 { 37 InstIcmpC op = context.GetOp<InstIcmpC>(); 38 39 var srcA = GetSrcReg(context, op.SrcA); 40 var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); 41 var srcC = GetSrcReg(context, op.SrcC); 42 43 EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); 44 } 45 46 public static void IcmpRc(EmitterContext context) 47 { 48 InstIcmpRc op = context.GetOp<InstIcmpRc>(); 49 50 var srcA = GetSrcReg(context, op.SrcA); 51 var srcB = GetSrcReg(context, op.SrcC); 52 var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); 53 54 EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); 55 } 56 57 public static void IsetR(EmitterContext context) 58 { 59 InstIsetR op = context.GetOp<InstIsetR>(); 60 61 var srcA = GetSrcReg(context, op.SrcA); 62 var srcB = GetSrcReg(context, op.SrcB); 63 64 EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); 65 } 66 67 public static void IsetI(EmitterContext context) 68 { 69 InstIsetI op = context.GetOp<InstIsetI>(); 70 71 var srcA = GetSrcReg(context, op.SrcA); 72 var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); 73 74 EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); 75 } 76 77 public static void IsetC(EmitterContext context) 78 { 79 InstIsetC op = context.GetOp<InstIsetC>(); 80 81 var srcA = GetSrcReg(context, op.SrcA); 82 var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); 83 84 EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); 85 } 86 87 public static void IsetpR(EmitterContext context) 88 { 89 InstIsetpR op = context.GetOp<InstIsetpR>(); 90 91 var srcA = GetSrcReg(context, op.SrcA); 92 var srcB = GetSrcReg(context, op.SrcB); 93 94 EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); 95 } 96 97 public static void IsetpI(EmitterContext context) 98 { 99 InstIsetpI op = context.GetOp<InstIsetpI>(); 100 101 var srcA = GetSrcReg(context, op.SrcA); 102 var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); 103 104 EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); 105 } 106 107 public static void IsetpC(EmitterContext context) 108 { 109 InstIsetpC op = context.GetOp<InstIsetpC>(); 110 111 var srcA = GetSrcReg(context, op.SrcA); 112 var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); 113 114 EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); 115 } 116 117 private static void EmitIcmp( 118 EmitterContext context, 119 IComp cmpOp, 120 Operand srcA, 121 Operand srcB, 122 Operand srcC, 123 int rd, 124 bool isSigned) 125 { 126 Operand cmpRes = GetIntComparison(context, cmpOp, srcC, Const(0), isSigned); 127 128 Operand res = context.ConditionalSelect(cmpRes, srcA, srcB); 129 130 context.Copy(GetDest(rd), res); 131 } 132 133 private static void EmitIset( 134 EmitterContext context, 135 IComp cmpOp, 136 BoolOp logicOp, 137 Operand srcA, 138 Operand srcB, 139 int srcPred, 140 bool srcPredInv, 141 int rd, 142 bool boolFloat, 143 bool isSigned, 144 bool extended, 145 bool writeCC) 146 { 147 Operand res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended); 148 Operand pred = GetPredicate(context, srcPred, srcPredInv); 149 150 res = GetPredLogicalOp(context, logicOp, res, pred); 151 152 Operand dest = GetDest(rd); 153 154 if (boolFloat) 155 { 156 res = context.ConditionalSelect(res, ConstF(1), Const(0)); 157 158 context.Copy(dest, res); 159 160 SetFPZnFlags(context, res, writeCC); 161 } 162 else 163 { 164 context.Copy(dest, res); 165 166 SetZnFlags(context, res, writeCC, extended); 167 } 168 } 169 170 private static void EmitIsetp( 171 EmitterContext context, 172 IComp cmpOp, 173 BoolOp logicOp, 174 Operand srcA, 175 Operand srcB, 176 int srcPred, 177 bool srcPredInv, 178 int destPred, 179 int destPredInv, 180 bool isSigned, 181 bool extended) 182 { 183 Operand p0Res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended); 184 Operand p1Res = context.BitwiseNot(p0Res); 185 Operand pred = GetPredicate(context, srcPred, srcPredInv); 186 187 p0Res = GetPredLogicalOp(context, logicOp, p0Res, pred); 188 p1Res = GetPredLogicalOp(context, logicOp, p1Res, pred); 189 190 context.Copy(Register(destPred, RegisterType.Predicate), p0Res); 191 context.Copy(Register(destPredInv, RegisterType.Predicate), p1Res); 192 } 193 194 private static Operand GetIntComparison( 195 EmitterContext context, 196 IComp cond, 197 Operand srcA, 198 Operand srcB, 199 bool isSigned, 200 bool extended) 201 { 202 return extended 203 ? GetIntComparisonExtended(context, cond, srcA, srcB, isSigned) 204 : GetIntComparison(context, cond, srcA, srcB, isSigned); 205 } 206 207 private static Operand GetIntComparisonExtended(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned) 208 { 209 Operand res; 210 211 if (cond == IComp.T) 212 { 213 res = Const(IrConsts.True); 214 } 215 else if (cond == IComp.F) 216 { 217 res = Const(IrConsts.False); 218 } 219 else 220 { 221 res = context.ISubtract(srcA, srcB); 222 #pragma warning disable IDE0059 // Remove unnecessary value assignment 223 res = context.IAdd(res, context.BitwiseNot(GetCF())); 224 #pragma warning restore IDE0059 225 226 switch (cond) 227 { 228 case IComp.Eq: // r = xh == yh && xl == yl 229 res = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetZF()); 230 break; 231 case IComp.Lt: // r = xh < yh || (xh == yh && xl < yl) 232 Operand notC = context.BitwiseNot(GetCF()); 233 Operand prevLt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notC); 234 res = isSigned 235 ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLt) 236 : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLt); 237 break; 238 case IComp.Le: // r = xh < yh || (xh == yh && xl <= yl) 239 Operand zOrNotC = context.BitwiseOr(GetZF(), context.BitwiseNot(GetCF())); 240 Operand prevLe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), zOrNotC); 241 res = isSigned 242 ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLe) 243 : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLe); 244 break; 245 case IComp.Gt: // r = xh > yh || (xh == yh && xl > yl) 246 Operand notZAndC = context.BitwiseAnd(context.BitwiseNot(GetZF()), GetCF()); 247 Operand prevGt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notZAndC); 248 res = isSigned 249 ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGt) 250 : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGt); 251 break; 252 case IComp.Ge: // r = xh > yh || (xh == yh && xl >= yl) 253 Operand prevGe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetCF()); 254 res = isSigned 255 ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGe) 256 : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGe); 257 break; 258 case IComp.Ne: // r = xh != yh || xl != yl 259 res = context.BitwiseOr(context.ICompareNotEqual(srcA, srcB), context.BitwiseNot(GetZF())); 260 break; 261 default: 262 throw new ArgumentException($"Unexpected condition \"{cond}\"."); 263 } 264 } 265 266 return res; 267 } 268 269 private static Operand GetIntComparison(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned) 270 { 271 Operand res; 272 273 if (cond == IComp.T) 274 { 275 res = Const(IrConsts.True); 276 } 277 else if (cond == IComp.F) 278 { 279 res = Const(IrConsts.False); 280 } 281 else 282 { 283 var inst = cond switch 284 { 285 IComp.Lt => Instruction.CompareLessU32, 286 IComp.Eq => Instruction.CompareEqual, 287 IComp.Le => Instruction.CompareLessOrEqualU32, 288 IComp.Gt => Instruction.CompareGreaterU32, 289 IComp.Ne => Instruction.CompareNotEqual, 290 IComp.Ge => Instruction.CompareGreaterOrEqualU32, 291 _ => throw new InvalidOperationException($"Unexpected condition \"{cond}\"."), 292 }; 293 294 if (isSigned) 295 { 296 switch (cond) 297 { 298 case IComp.Lt: 299 inst = Instruction.CompareLess; 300 break; 301 case IComp.Le: 302 inst = Instruction.CompareLessOrEqual; 303 break; 304 case IComp.Gt: 305 inst = Instruction.CompareGreater; 306 break; 307 case IComp.Ge: 308 inst = Instruction.CompareGreaterOrEqual; 309 break; 310 } 311 } 312 313 res = context.Add(inst, Local(), srcA, srcB); 314 } 315 316 return res; 317 } 318 } 319 }