From 4b7c7dab9e33faaf4eb58342f1f7ad8ada354591 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 Jan 2021 20:59:47 -0300 Subject: [PATCH] Support multiple destination operands on shader IR and shuffle predicates (#1964) * Support multiple destination operands on shader IR and shuffle predicates * Cache version change --- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- .../CodeGen/Glsl/HelperFunctions/Shuffle.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleDown.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleUp.glsl | 5 +- .../Glsl/HelperFunctions/ShuffleXor.glsl | 5 +- .../Glsl/Instructions/InstGenHelper.cs | 14 +-- .../Instructions/InstEmitMove.cs | 24 ++--- .../IntermediateRepresentation/INode.cs | 2 + .../IntermediateRepresentation/Operation.cs | 98 +++++++++++++++---- .../IntermediateRepresentation/PhiNode.cs | 13 +++ .../StructuredIr/InstructionInfo.cs | 14 +-- .../StructuredIr/StructuredProgram.cs | 12 ++- .../Translation/EmitterContext.cs | 11 +++ .../Translation/EmitterContextInsts.cs | 16 +-- .../Translation/Optimizations/Optimizer.cs | 33 ++++++- Ryujinx.Graphics.Shader/Translation/Ssa.cs | 19 ++-- 16 files changed, 199 insertions(+), 79 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index f3e4679b..f4fef145 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 1790; + private const ulong ShaderCodeGenVersion = 1964; /// /// Creates a new instance of the shader cache. diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl index 380bc581..356bdd79 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl @@ -1,9 +1,10 @@ -float Helper_Shuffle(float x, uint index, uint mask) +float Helper_Shuffle(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = (index & ~segMask) | minThreadId; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl index 46750f20..a79b90e2 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl @@ -1,9 +1,10 @@ -float Helper_ShuffleDown(float x, uint index, uint mask) +float Helper_ShuffleDown(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = gl_SubGroupInvocationARB + index; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl index 2bc83469..4e74f217 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl @@ -1,8 +1,9 @@ -float Helper_ShuffleUp(float x, uint index, uint mask) +float Helper_ShuffleUp(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint srcThreadId = gl_SubGroupInvocationARB - index; - return (srcThreadId >= minThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId >= minThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl index 1049e181..0631472b 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl @@ -1,9 +1,10 @@ -float Helper_ShuffleXor(float x, uint index, uint mask) +float Helper_ShuffleXor(float x, uint index, uint mask, out bool valid) { uint clamp = mask & 0x1fu; uint segMask = (mask >> 8) & 0x1fu; uint minThreadId = gl_SubGroupInvocationARB & segMask; uint maxThreadId = minThreadId | (clamp & ~segMask); uint srcThreadId = gl_SubGroupInvocationARB ^ index; - return (srcThreadId <= maxThreadId) ? readInvocationARB(x, srcThreadId) : x; + valid = srcThreadId <= maxThreadId; + return valid ? readInvocationARB(x, srcThreadId) : x; } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs index 5f5574c3..f3774a60 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -88,13 +88,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.LoopContinue, InstType.OpNullary, "continue"); Add(Instruction.PackDouble2x32, InstType.Special); Add(Instruction.PackHalf2x16, InstType.Special); - Add(Instruction.ShiftLeft, InstType.OpBinary, "<<", 3); - Add(Instruction.ShiftRightS32, InstType.OpBinary, ">>", 3); - Add(Instruction.ShiftRightU32, InstType.OpBinary, ">>", 3); - Add(Instruction.Shuffle, InstType.CallTernary, HelperFunctionNames.Shuffle); - Add(Instruction.ShuffleDown, InstType.CallTernary, HelperFunctionNames.ShuffleDown); - Add(Instruction.ShuffleUp, InstType.CallTernary, HelperFunctionNames.ShuffleUp); - Add(Instruction.ShuffleXor, InstType.CallTernary, HelperFunctionNames.ShuffleXor); Add(Instruction.Maximum, InstType.CallBinary, "max"); Add(Instruction.MaximumU32, InstType.CallBinary, "max"); Add(Instruction.MemoryBarrier, InstType.CallNullary, "memoryBarrier"); @@ -107,6 +100,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Add(Instruction.ReciprocalSquareRoot, InstType.CallUnary, "inversesqrt"); Add(Instruction.Return, InstType.OpNullary, "return"); Add(Instruction.Round, InstType.CallUnary, "roundEven"); + Add(Instruction.ShiftLeft, InstType.OpBinary, "<<", 3); + Add(Instruction.ShiftRightS32, InstType.OpBinary, ">>", 3); + Add(Instruction.ShiftRightU32, InstType.OpBinary, ">>", 3); + Add(Instruction.Shuffle, InstType.CallQuaternary, HelperFunctionNames.Shuffle); + Add(Instruction.ShuffleDown, InstType.CallQuaternary, HelperFunctionNames.ShuffleDown); + Add(Instruction.ShuffleUp, InstType.CallQuaternary, HelperFunctionNames.ShuffleUp); + Add(Instruction.ShuffleXor, InstType.CallQuaternary, HelperFunctionNames.ShuffleXor); Add(Instruction.Sine, InstType.CallUnary, "sin"); Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt"); Add(Instruction.StoreLocal, InstType.Special); diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs index 264c732d..085325ee 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs @@ -118,25 +118,17 @@ namespace Ryujinx.Graphics.Shader.Instructions Operand srcB = op.IsBImmediate ? Const(op.ImmediateB) : Register(op.Rb); Operand srcC = op.IsCImmediate ? Const(op.ImmediateC) : Register(op.Rc); - Operand res = null; - - switch (op.ShuffleType) + (Operand res, Operand valid) = op.ShuffleType switch { - case ShuffleType.Indexed: - res = context.Shuffle(srcA, srcB, srcC); - break; - case ShuffleType.Up: - res = context.ShuffleUp(srcA, srcB, srcC); - break; - case ShuffleType.Down: - res = context.ShuffleDown(srcA, srcB, srcC); - break; - case ShuffleType.Butterfly: - res = context.ShuffleXor(srcA, srcB, srcC); - break; - } + ShuffleType.Indexed => context.Shuffle(srcA, srcB, srcC), + ShuffleType.Up => context.ShuffleUp(srcA, srcB, srcC), + ShuffleType.Down => context.ShuffleDown(srcA, srcB, srcC), + ShuffleType.Butterfly => context.ShuffleXor(srcA, srcB, srcC), + _ => (null, null) + }; context.Copy(GetDest(context), res); + context.Copy(pred, valid); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs index 48dda24b..0f545e56 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs @@ -4,8 +4,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { Operand Dest { get; set; } + int DestsCount { get; } int SourcesCount { get; } + Operand GetDest(int index); Operand GetSource(int index); void SetSource(int index, Operand operand); diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs index a86a278a..4f0801b7 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs @@ -6,25 +6,42 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { public Instruction Inst { get; private set; } - private Operand _dest; + private Operand[] _dests; public Operand Dest { - get => _dest; - set => _dest = AssignDest(value); + get + { + return _dests.Length != 0 ? _dests[0] : null; + } + set + { + if (value != null && value.Type == OperandType.LocalVariable) + { + value.AsgOp = this; + } + + if (value != null) + { + _dests = new[] { value }; + } + else + { + _dests = Array.Empty(); + } + } } + public int DestsCount => _dests.Length; + private Operand[] _sources; public int SourcesCount => _sources.Length; public int Index { get; } - public Operation(Instruction inst, Operand dest, params Operand[] sources) + private Operation(Operand[] sources) { - Inst = inst; - Dest = dest; - // The array may be modified externally, so we store a copy. _sources = (Operand[])sources.Clone(); @@ -39,11 +56,42 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } - public Operation( - Instruction inst, - int index, - Operand dest, - params Operand[] sources) : this(inst, dest, sources) + public Operation(Instruction inst, int index, Operand[] dests, Operand[] sources) : this(sources) + { + Inst = inst; + Index = index; + + // The array may be modified externally, so we store a copy. + _dests = (Operand[])dests.Clone(); + + for (int dstIndex = 0; dstIndex < dests.Length; dstIndex++) + { + Operand dest = dests[dstIndex]; + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + } + } + + public Operation(Instruction inst, Operand dest, params Operand[] sources) : this(sources) + { + Inst = inst; + + if (dest != null) + { + dest.AsgOp = this; + + _dests = new[] { dest }; + } + else + { + _dests = Array.Empty(); + } + } + + public Operation(Instruction inst, int index, Operand dest, params Operand[] sources) : this(inst, dest, sources) { Index = index; } @@ -67,14 +115,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } - private Operand AssignDest(Operand dest) + public Operand GetDest(int index) { - if (dest != null && dest.Type == OperandType.LocalVariable) - { - dest.AsgOp = this; - } - - return dest; + return _dests[index]; } public Operand GetSource(int index) @@ -82,6 +125,23 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation return _sources[index]; } + public void SetDest(int index, Operand dest) + { + Operand oldDest = _dests[index]; + + if (oldDest != null && oldDest.Type == OperandType.LocalVariable) + { + oldDest.AsgOp = null; + } + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + _dests[index] = dest; + } + public void SetSource(int index, Operand source) { Operand oldSrc = _sources[index]; diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs index 13ff41bd..8fa25ae9 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.IntermediateRepresentation @@ -12,6 +13,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation set => _dest = AssignDest(value); } + public int DestsCount => _dest != null ? 1 : 0; + private HashSet _blocks; private class PhiSource @@ -64,6 +67,16 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation } } + public Operand GetDest(int index) + { + if (index != 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return _dest; + } + public Operand GetSource(int index) { return _sources[index].Operand; diff --git a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs index fcf39cc0..88cfe729 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs @@ -94,13 +94,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); Add(Instruction.LogicalNot, VariableType.Bool, VariableType.Bool); Add(Instruction.LogicalOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); - Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int); - Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int); - Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int); - Add(Instruction.Shuffle, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleDown, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleUp, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); - Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32); Add(Instruction.Maximum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); Add(Instruction.MaximumU32, VariableType.U32, VariableType.U32, VariableType.U32); Add(Instruction.Minimum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); @@ -113,6 +106,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr Add(Instruction.PackHalf2x16, VariableType.U32, VariableType.F32, VariableType.F32); Add(Instruction.ReciprocalSquareRoot, VariableType.Scalar, VariableType.Scalar); Add(Instruction.Round, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int); + Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int); + Add(Instruction.Shuffle, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleDown, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleUp, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); + Add(Instruction.ShuffleXor, VariableType.F32, VariableType.F32, VariableType.U32, VariableType.U32, VariableType.Bool); Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar); Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar); Add(Instruction.StoreGlobal, VariableType.None, VariableType.S32, VariableType.S32, VariableType.U32); diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs index 8c73e698..497cffc8 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgram.cs @@ -77,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr bool isCall = inst == Instruction.Call; int sourcesCount = operation.SourcesCount; + int outDestsCount = operation.DestsCount != 0 ? operation.DestsCount - 1 : 0; List callOutOperands = new List(); @@ -93,7 +94,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr sourcesCount += callOutOperands.Count; } - IAstNode[] sources = new IAstNode[sourcesCount]; + IAstNode[] sources = new IAstNode[sourcesCount + outDestsCount]; for (int index = 0; index < operation.SourcesCount; index++) { @@ -110,6 +111,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr callOutOperands.Clear(); } + for (int index = 0; index < outDestsCount; index++) + { + AstOperand oper = context.GetOperandDef(operation.GetDest(1 + index)); + + oper.VarType = InstructionInfo.GetSrcVarType(inst, sourcesCount + index); + + sources[sourcesCount + index] = oper; + } + AstTextureOperation GetAstTextureOperation(TextureOperation texOp) { return new AstTextureOperation( diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index d5d30f12..df6b0839 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -37,6 +37,17 @@ namespace Ryujinx.Graphics.Shader.Translation return dest; } + public (Operand, Operand) Add(Instruction inst, (Operand, Operand) dest, params Operand[] sources) + { + Operand[] dests = new[] { dest.Item1, dest.Item2 }; + + Operation operation = new Operation(inst, 0, dests, sources); + + Add(operation); + + return dest; + } + public void Add(Operation operation) { _operations.Add(operation); diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs index b2418c2e..dcefb591 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs @@ -588,24 +588,24 @@ namespace Ryujinx.Graphics.Shader.Translation return context.Add(Instruction.ShiftRightU32, Local(), a, b); } - public static Operand Shuffle(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) Shuffle(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.Shuffle, Local(), a, b, c); + return context.Add(Instruction.Shuffle, (Local(), Local()), a, b, c); } - public static Operand ShuffleDown(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleDown(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleDown, Local(), a, b, c); + return context.Add(Instruction.ShuffleDown, (Local(), Local()), a, b, c); } - public static Operand ShuffleUp(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleUp(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleUp, Local(), a, b, c); + return context.Add(Instruction.ShuffleUp, (Local(), Local()), a, b, c); } - public static Operand ShuffleXor(this EmitterContext context, Operand a, Operand b, Operand c) + public static (Operand, Operand) ShuffleXor(this EmitterContext context, Operand a, Operand b, Operand c) { - return context.Add(Instruction.ShuffleXor, Local(), a, b, c); + return context.Add(Instruction.ShuffleXor, (Local(), Local()), a, b, c); } public static Operand StoreGlobal(this EmitterContext context, Operand a, Operand b, Operand c) diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index 32c7d2f0..9a0815c3 100644 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) || (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation))) { - if (operation.Dest.UseOps.Count == 0) + if (DestHasNoUses(operation)) { RemoveNode(block, node); } @@ -260,6 +260,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (src.UseOps.Remove(node) && src.UseOps.Count == 0) { + Debug.Assert(src.AsgOp != null); nodes.Enqueue(src.AsgOp); } } @@ -268,7 +269,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool IsUnused(INode node) { - return !HasSideEffects(node) && DestIsLocalVar(node) && node.Dest.UseOps.Count == 0; + return !HasSideEffects(node) && DestIsLocalVar(node) && DestHasNoUses(node); } private static bool HasSideEffects(INode node) @@ -298,7 +299,33 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool DestIsLocalVar(INode node) { - return node.Dest != null && node.Dest.Type == OperandType.LocalVariable; + if (node.DestsCount == 0) + { + return false; + } + + for (int index = 0; index < node.DestsCount; index++) + { + if (node.GetDest(index).Type != OperandType.LocalVariable) + { + return false; + } + } + + return true; + } + + private static bool DestHasNoUses(INode node) + { + for (int index = 0; index < node.DestsCount; index++) + { + if (node.GetDest(index).UseOps.Count != 0) + { + return false; + } + } + + return true; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Ssa.cs b/Ryujinx.Graphics.Shader/Translation/Ssa.cs index a4d763be..ff812e64 100644 --- a/Ryujinx.Graphics.Shader/Translation/Ssa.cs +++ b/Ryujinx.Graphics.Shader/Translation/Ssa.cs @@ -116,13 +116,18 @@ namespace Ryujinx.Graphics.Shader.Translation operation.SetSource(index, RenameLocal(operation.GetSource(index))); } - if (operation.Dest != null && operation.Dest.Type == OperandType.Register) + for (int index = 0; index < operation.DestsCount; index++) { - Operand local = Local(); + Operand dest = operation.GetDest(index); - localDefs[GetKeyFromRegister(operation.Dest.GetRegister())] = local; + if (dest.Type == OperandType.Register) + { + Operand local = Local(); - operation.Dest = local; + localDefs[GetKeyFromRegister(dest.GetRegister())] = local; + + operation.SetDest(index, local); + } } } @@ -185,9 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation return operand; } - LinkedListNode node = block.Operations.First; - - while (node != null) + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) { if (node.Value is Operation operation) { @@ -196,8 +199,6 @@ namespace Ryujinx.Graphics.Shader.Translation operation.SetSource(index, RenameGlobal(operation.GetSource(index))); } } - - node = node.Next; } } }