diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs new file mode 100644 index 00000000..dcdb189f --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitIntegerComparison.cs @@ -0,0 +1,310 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void IcmpR(EmitterContext context) + { + InstIcmpR op = context.GetOp<InstIcmpR>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcB); + var srcC = GetSrcReg(context, op.SrcC); + + EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); + } + + public static void IcmpI(EmitterContext context) + { + InstIcmpI op = context.GetOp<InstIcmpI>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); + var srcC = GetSrcReg(context, op.SrcC); + + EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); + } + + public static void IcmpC(EmitterContext context) + { + InstIcmpC op = context.GetOp<InstIcmpC>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); + var srcC = GetSrcReg(context, op.SrcC); + + EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); + } + + public static void IcmpRc(EmitterContext context) + { + InstIcmpRc op = context.GetOp<InstIcmpRc>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcC); + var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); + + EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed); + } + + public static void IsetR(EmitterContext context) + { + InstIsetR op = context.GetOp<InstIsetR>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcB); + + EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); + } + + public static void IsetI(EmitterContext context) + { + InstIsetI op = context.GetOp<InstIsetI>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); + + EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); + } + + public static void IsetC(EmitterContext context) + { + InstIsetC op = context.GetOp<InstIsetC>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); + + EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC); + } + + public static void IsetpR(EmitterContext context) + { + InstIsetpR op = context.GetOp<InstIsetpR>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcReg(context, op.SrcB); + + EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); + } + + public static void IsetpI(EmitterContext context) + { + InstIsetpI op = context.GetOp<InstIsetpI>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20)); + + EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); + } + + public static void IsetpC(EmitterContext context) + { + InstIsetpC op = context.GetOp<InstIsetpC>(); + + var srcA = GetSrcReg(context, op.SrcA); + var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset); + + EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X); + } + + private static void EmitIcmp( + EmitterContext context, + IComp cmpOp, + Operand srcA, + Operand srcB, + Operand srcC, + int rd, + bool isSigned) + { + Operand cmpRes = GetIntComparison(context, cmpOp, srcC, Const(0), isSigned); + + Operand res = context.ConditionalSelect(cmpRes, srcA, srcB); + + context.Copy(GetDest(rd), res); + } + + private static void EmitIset( + EmitterContext context, + IComp cmpOp, + BoolOp logicOp, + Operand srcA, + Operand srcB, + int srcPred, + bool srcPredInv, + int rd, + bool boolFloat, + bool isSigned, + bool extended, + bool writeCC) + { + Operand res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended); + Operand pred = GetPredicate(context, srcPred, srcPredInv); + + res = GetPredLogicalOp(context, logicOp, res, pred); + + Operand dest = GetDest(rd); + + if (boolFloat) + { + res = context.ConditionalSelect(res, ConstF(1), Const(0)); + + context.Copy(dest, res); + + SetFPZnFlags(context, res, writeCC); + } + else + { + context.Copy(dest, res); + + SetZnFlags(context, res, writeCC, extended); + } + } + + private static void EmitIsetp( + EmitterContext context, + IComp cmpOp, + BoolOp logicOp, + Operand srcA, + Operand srcB, + int srcPred, + bool srcPredInv, + int destPred, + int destPredInv, + bool isSigned, + bool extended) + { + Operand p0Res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended); + Operand p1Res = context.BitwiseNot(p0Res); + Operand pred = GetPredicate(context, srcPred, srcPredInv); + + p0Res = GetPredLogicalOp(context, logicOp, p0Res, pred); + p1Res = GetPredLogicalOp(context, logicOp, p1Res, pred); + + context.Copy(Register(destPred, RegisterType.Predicate), p0Res); + context.Copy(Register(destPredInv, RegisterType.Predicate), p1Res); + } + + private static Operand GetIntComparison( + EmitterContext context, + IComp cond, + Operand srcA, + Operand srcB, + bool isSigned, + bool extended) + { + return extended + ? GetIntComparisonExtended(context, cond, srcA, srcB, isSigned) + : GetIntComparison(context, cond, srcA, srcB, isSigned); + } + + private static Operand GetIntComparisonExtended(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned) + { + Operand res; + + if (cond == IComp.T) + { + res = Const(IrConsts.True); + } + else if (cond == IComp.F) + { + res = Const(IrConsts.False); + } + else + { + res = context.ISubtract(srcA, srcB); + res = context.IAdd(res, context.BitwiseNot(GetCF())); + + switch (cond) + { + case IComp.Eq: // r = xh == yh && xl == yl + res = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetZF()); + break; + case IComp.Lt: // r = xh < yh || (xh == yh && xl < yl) + Operand notC = context.BitwiseNot(GetCF()); + Operand prevLt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notC); + res = isSigned + ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLt) + : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLt); + break; + case IComp.Le: // r = xh < yh || (xh == yh && xl <= yl) + Operand zOrNotC = context.BitwiseOr(GetZF(), context.BitwiseNot(GetCF())); + Operand prevLe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), zOrNotC); + res = isSigned + ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLe) + : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLe); + break; + case IComp.Gt: // r = xh > yh || (xh == yh && xl > yl) + Operand notZAndC = context.BitwiseAnd(context.BitwiseNot(GetZF()), GetCF()); + Operand prevGt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notZAndC); + res = isSigned + ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGt) + : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGt); + break; + case IComp.Ge: // r = xh > yh || (xh == yh && xl >= yl) + Operand prevGe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetCF()); + res = isSigned + ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGe) + : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGe); + break; + case IComp.Ne: // r = xh != yh || xl != yl + res = context.BitwiseOr(context.ICompareNotEqual(srcA, srcB), context.BitwiseNot(GetZF())); + break; + default: + throw new ArgumentException($"Unexpected condition \"{cond}\"."); + } + } + + return res; + } + + private static Operand GetIntComparison(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned) + { + Operand res; + + if (cond == IComp.T) + { + res = Const(IrConsts.True); + } + else if (cond == IComp.F) + { + res = Const(IrConsts.False); + } + else + { + var inst = cond switch + { + IComp.Lt => Instruction.CompareLessU32, + IComp.Eq => Instruction.CompareEqual, + IComp.Le => Instruction.CompareLessOrEqualU32, + IComp.Gt => Instruction.CompareGreaterU32, + IComp.Ne => Instruction.CompareNotEqual, + IComp.Ge => Instruction.CompareGreaterOrEqualU32, + _ => throw new InvalidOperationException($"Unexpected condition \"{cond}\".") + }; + + if (isSigned) + { + switch (cond) + { + case IComp.Lt: inst = Instruction.CompareLess; break; + case IComp.Le: inst = Instruction.CompareLessOrEqual; break; + case IComp.Gt: inst = Instruction.CompareGreater; break; + case IComp.Ge: inst = Instruction.CompareGreaterOrEqual; break; + } + } + + res = context.Add(inst, Local(), srcA, srcB); + } + + return res; + } + } +}
\ No newline at end of file |