diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Graphics.Shader/Translation/Optimizations | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/Optimizations')
8 files changed, 0 insertions, 1786 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs deleted file mode 100644 index 0c196c4d..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ /dev/null @@ -1,263 +0,0 @@ -using Ryujinx.Graphics.Shader.Instructions; -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - class BindlessElimination - { - public static void RunPass(BasicBlock block, ShaderConfig config) - { - // We can turn a bindless into regular access by recognizing the pattern - // produced by the compiler for separate texture and sampler. - // We check for the following conditions: - // - The handle is a constant buffer value. - // - The handle is the result of a bitwise OR logical operation. - // - Both sources of the OR operation comes from a constant buffer. - for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next) - { - if (!(node.Value is TextureOperation texOp)) - { - continue; - } - - if ((texOp.Flags & TextureFlags.Bindless) == 0) - { - continue; - } - - if (texOp.Inst == Instruction.Lod || - texOp.Inst == Instruction.TextureSample || - texOp.Inst == Instruction.TextureSize) - { - Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); - - // Some instructions do not encode an accurate sampler type: - // - Most instructions uses the same type for 1D and Buffer. - // - Query instructions may not have any type. - // For those cases, we need to try getting the type from current GPU state, - // as long bindless elimination is successful and we know where the texture descriptor is located. - bool rewriteSamplerType = - texOp.Type == SamplerType.TextureBuffer || - texOp.Inst == Instruction.TextureSize; - - if (bindlessHandle.Type == OperandType.ConstantBuffer) - { - SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType, isImage: false); - continue; - } - - if (!(bindlessHandle.AsgOp is Operation handleCombineOp)) - { - continue; - } - - if (handleCombineOp.Inst != Instruction.BitwiseOr) - { - continue; - } - - Operand src0 = Utils.FindLastOperation(handleCombineOp.GetSource(0), block); - Operand src1 = Utils.FindLastOperation(handleCombineOp.GetSource(1), block); - - // For cases where we have a constant, ensure that the constant is always - // the second operand. - // Since this is a commutative operation, both are fine, - // and having a "canonical" representation simplifies some checks below. - if (src0.Type == OperandType.Constant && src1.Type != OperandType.Constant) - { - Operand temp = src1; - src1 = src0; - src0 = temp; - } - - TextureHandleType handleType = TextureHandleType.SeparateSamplerHandle; - - // Try to match the following patterns: - // Masked pattern: - // - samplerHandle = samplerHandle & 0xFFF00000; - // - textureHandle = textureHandle & 0xFFFFF; - // - combinedHandle = samplerHandle | textureHandle; - // Where samplerHandle and textureHandle comes from a constant buffer. - // Shifted pattern: - // - samplerHandle = samplerId << 20; - // - combinedHandle = samplerHandle | textureHandle; - // Where samplerId and textureHandle comes from a constant buffer. - // Constant pattern: - // - combinedHandle = samplerHandleConstant | textureHandle; - // Where samplerHandleConstant is a constant value, and textureHandle comes from a constant buffer. - if (src0.AsgOp is Operation src0AsgOp) - { - if (src1.AsgOp is Operation src1AsgOp && - src0AsgOp.Inst == Instruction.BitwiseAnd && - src1AsgOp.Inst == Instruction.BitwiseAnd) - { - src0 = GetSourceForMaskedHandle(src0AsgOp, 0xFFFFF); - src1 = GetSourceForMaskedHandle(src1AsgOp, 0xFFF00000); - - // The OR operation is commutative, so we can also try to swap the operands to get a match. - if (src0 == null || src1 == null) - { - src0 = GetSourceForMaskedHandle(src1AsgOp, 0xFFFFF); - src1 = GetSourceForMaskedHandle(src0AsgOp, 0xFFF00000); - } - - if (src0 == null || src1 == null) - { - continue; - } - } - else if (src0AsgOp.Inst == Instruction.ShiftLeft) - { - Operand shift = src0AsgOp.GetSource(1); - - if (shift.Type == OperandType.Constant && shift.Value == 20) - { - src0 = src1; - src1 = src0AsgOp.GetSource(0); - handleType = TextureHandleType.SeparateSamplerId; - } - } - } - else if (src1.AsgOp is Operation src1AsgOp && src1AsgOp.Inst == Instruction.ShiftLeft) - { - Operand shift = src1AsgOp.GetSource(1); - - if (shift.Type == OperandType.Constant && shift.Value == 20) - { - src1 = src1AsgOp.GetSource(0); - handleType = TextureHandleType.SeparateSamplerId; - } - } - else if (src1.Type == OperandType.Constant && (src1.Value & 0xfffff) == 0) - { - handleType = TextureHandleType.SeparateConstantSamplerHandle; - } - - if (src0.Type != OperandType.ConstantBuffer) - { - continue; - } - - if (handleType == TextureHandleType.SeparateConstantSamplerHandle) - { - SetHandle( - config, - texOp, - TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType), - TextureHandle.PackSlots(src0.GetCbufSlot(), 0), - rewriteSamplerType, - isImage: false); - } - else if (src1.Type == OperandType.ConstantBuffer) - { - SetHandle( - config, - texOp, - TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), - TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), - rewriteSamplerType, - isImage: false); - } - } - else if (texOp.Inst == Instruction.ImageLoad || - texOp.Inst == Instruction.ImageStore || - texOp.Inst == Instruction.ImageAtomic) - { - Operand src0 = Utils.FindLastOperation(texOp.GetSource(0), block); - - if (src0.Type == OperandType.ConstantBuffer) - { - int cbufOffset = src0.GetCbufOffset(); - int cbufSlot = src0.GetCbufSlot(); - - if (texOp.Format == TextureFormat.Unknown) - { - if (texOp.Inst == Instruction.ImageAtomic) - { - texOp.Format = config.GetTextureFormatAtomic(cbufOffset, cbufSlot); - } - else - { - texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot); - } - } - - bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer; - - SetHandle(config, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); - } - } - } - } - - private static Operand GetSourceForMaskedHandle(Operation asgOp, uint mask) - { - // Assume it was already checked that the operation is bitwise AND. - Operand src0 = asgOp.GetSource(0); - Operand src1 = asgOp.GetSource(1); - - if (src0.Type == OperandType.ConstantBuffer && src1.Type == OperandType.ConstantBuffer) - { - // We can't check if the mask matches here as both operands are from a constant buffer. - // Be optimistic and assume it matches. Avoid constant buffer 1 as official drivers - // uses this one to store compiler constants. - return src0.GetCbufSlot() == 1 ? src1 : src0; - } - else if (src0.Type == OperandType.ConstantBuffer && src1.Type == OperandType.Constant) - { - if ((uint)src1.Value == mask) - { - return src0; - } - } - else if (src0.Type == OperandType.Constant && src1.Type == OperandType.ConstantBuffer) - { - if ((uint)src0.Value == mask) - { - return src1; - } - } - - return null; - } - - private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage) - { - texOp.SetHandle(cbufOffset, cbufSlot); - - if (rewriteSamplerType) - { - SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot); - - if (texOp.Inst.IsTextureQuery()) - { - texOp.Type = newType; - } - else if (texOp.Type == SamplerType.TextureBuffer && newType == SamplerType.Texture1D) - { - int coordsCount = 1; - - if (InstEmit.Sample1DAs2D) - { - newType = SamplerType.Texture2D; - texOp.InsertSource(coordsCount++, OperandHelper.Const(0)); - } - - if (!isImage && - (texOp.Flags & TextureFlags.IntCoords) != 0 && - (texOp.Flags & TextureFlags.LodLevel) == 0) - { - // IntCoords textures must always have explicit LOD. - texOp.SetLodLevelFlag(); - texOp.InsertSource(coordsCount, OperandHelper.Const(0)); - } - - texOp.Type = newType; - } - } - - config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset); - } - } -} diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs deleted file mode 100644 index ca46a1f5..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System.Collections.Generic; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class BindlessToIndexed - { - public static void RunPass(BasicBlock block, ShaderConfig config) - { - // We can turn a bindless texture access into a indexed access, - // as long the following conditions are true: - // - The handle is loaded using a LDC instruction. - // - The handle is loaded from the constant buffer with the handles (CB2 for NVN). - // - The load has a constant offset. - // The base offset of the array of handles on the constant buffer is the constant offset. - for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next) - { - if (!(node.Value is TextureOperation texOp)) - { - continue; - } - - if ((texOp.Flags & TextureFlags.Bindless) == 0) - { - continue; - } - - if (!(texOp.GetSource(0).AsgOp is Operation handleAsgOp)) - { - continue; - } - - if (handleAsgOp.Inst != Instruction.LoadConstant) - { - continue; - } - - Operand ldcSrc0 = handleAsgOp.GetSource(0); - Operand ldcSrc1 = handleAsgOp.GetSource(1); - - if (ldcSrc0.Type != OperandType.Constant || ldcSrc0.Value != 2) - { - continue; - } - - if (!(ldcSrc1.AsgOp is Operation shrOp) || shrOp.Inst != Instruction.ShiftRightU32) - { - continue; - } - - if (!(shrOp.GetSource(0).AsgOp is Operation addOp) || addOp.Inst != Instruction.Add) - { - continue; - } - - Operand addSrc1 = addOp.GetSource(1); - - if (addSrc1.Type != OperandType.Constant) - { - continue; - } - - TurnIntoIndexed(config, texOp, addSrc1.Value / 4); - - Operand index = Local(); - - Operand source = addOp.GetSource(0); - - Operation shrBy3 = new Operation(Instruction.ShiftRightU32, index, source, Const(3)); - - block.Operations.AddBefore(node, shrBy3); - - texOp.SetSource(0, index); - } - } - - private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle) - { - texOp.TurnIntoIndexed(handle); - config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, texOp.CbufSlot, handle); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs deleted file mode 100644 index c87d1474..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/BranchElimination.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class BranchElimination - { - public static bool RunPass(BasicBlock block) - { - if (block.HasBranch && IsRedundantBranch((Operation)block.GetLastOp(), Next(block))) - { - block.Branch = null; - - return true; - } - - return false; - } - - private static bool IsRedundantBranch(Operation current, BasicBlock nextBlock) - { - // Here we check that: - // - The current block ends with a branch. - // - The next block only contains a branch. - // - The branch on the next block is unconditional. - // - Both branches are jumping to the same location. - // In this case, the branch on the current block can be removed, - // as the next block is going to jump to the same place anyway. - if (nextBlock == null) - { - return false; - } - - if (!(nextBlock.Operations.First?.Value is Operation next)) - { - return false; - } - - if (next.Inst != Instruction.Branch) - { - return false; - } - - return current.Dest == next.Dest; - } - - private static BasicBlock Next(BasicBlock block) - { - block = block.Next; - - while (block != null && block.Operations.Count == 0) - { - if (block.HasBranch) - { - throw new InvalidOperationException("Found a bogus empty block that \"ends with a branch\"."); - } - - block = block.Next; - } - - return block; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs deleted file mode 100644 index 6729f077..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs +++ /dev/null @@ -1,346 +0,0 @@ -using Ryujinx.Common.Utilities; -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class ConstantFolding - { - public static void RunPass(Operation operation) - { - if (!AreAllSourcesConstant(operation)) - { - return; - } - - switch (operation.Inst) - { - case Instruction.Add: - EvaluateBinary(operation, (x, y) => x + y); - break; - - case Instruction.BitCount: - EvaluateUnary(operation, (x) => BitCount(x)); - break; - - case Instruction.BitwiseAnd: - EvaluateBinary(operation, (x, y) => x & y); - break; - - case Instruction.BitwiseExclusiveOr: - EvaluateBinary(operation, (x, y) => x ^ y); - break; - - case Instruction.BitwiseNot: - EvaluateUnary(operation, (x) => ~x); - break; - - case Instruction.BitwiseOr: - EvaluateBinary(operation, (x, y) => x | y); - break; - - case Instruction.BitfieldExtractS32: - BitfieldExtractS32(operation); - break; - - case Instruction.BitfieldExtractU32: - BitfieldExtractU32(operation); - break; - - case Instruction.Clamp: - EvaluateTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); - break; - - case Instruction.ClampU32: - EvaluateTernary(operation, (x, y, z) => (int)Math.Clamp((uint)x, (uint)y, (uint)z)); - break; - - case Instruction.CompareEqual: - EvaluateBinary(operation, (x, y) => x == y); - break; - - case Instruction.CompareGreater: - EvaluateBinary(operation, (x, y) => x > y); - break; - - case Instruction.CompareGreaterOrEqual: - EvaluateBinary(operation, (x, y) => x >= y); - break; - - case Instruction.CompareGreaterOrEqualU32: - EvaluateBinary(operation, (x, y) => (uint)x >= (uint)y); - break; - - case Instruction.CompareGreaterU32: - EvaluateBinary(operation, (x, y) => (uint)x > (uint)y); - break; - - case Instruction.CompareLess: - EvaluateBinary(operation, (x, y) => x < y); - break; - - case Instruction.CompareLessOrEqual: - EvaluateBinary(operation, (x, y) => x <= y); - break; - - case Instruction.CompareLessOrEqualU32: - EvaluateBinary(operation, (x, y) => (uint)x <= (uint)y); - break; - - case Instruction.CompareLessU32: - EvaluateBinary(operation, (x, y) => (uint)x < (uint)y); - break; - - case Instruction.CompareNotEqual: - EvaluateBinary(operation, (x, y) => x != y); - break; - - case Instruction.Divide: - EvaluateBinary(operation, (x, y) => y != 0 ? x / y : 0); - break; - - case Instruction.FP32 | Instruction.Add: - EvaluateFPBinary(operation, (x, y) => x + y); - break; - - case Instruction.FP32 | Instruction.Clamp: - EvaluateFPTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); - break; - - case Instruction.FP32 | Instruction.CompareEqual: - EvaluateFPBinary(operation, (x, y) => x == y); - break; - - case Instruction.FP32 | Instruction.CompareGreater: - EvaluateFPBinary(operation, (x, y) => x > y); - break; - - case Instruction.FP32 | Instruction.CompareGreaterOrEqual: - EvaluateFPBinary(operation, (x, y) => x >= y); - break; - - case Instruction.FP32 | Instruction.CompareLess: - EvaluateFPBinary(operation, (x, y) => x < y); - break; - - case Instruction.FP32 | Instruction.CompareLessOrEqual: - EvaluateFPBinary(operation, (x, y) => x <= y); - break; - - case Instruction.FP32 | Instruction.CompareNotEqual: - EvaluateFPBinary(operation, (x, y) => x != y); - break; - - case Instruction.FP32 | Instruction.Divide: - EvaluateFPBinary(operation, (x, y) => x / y); - break; - - case Instruction.FP32 | Instruction.Multiply: - EvaluateFPBinary(operation, (x, y) => x * y); - break; - - case Instruction.FP32 | Instruction.Negate: - EvaluateFPUnary(operation, (x) => -x); - break; - - case Instruction.FP32 | Instruction.Subtract: - EvaluateFPBinary(operation, (x, y) => x - y); - break; - - case Instruction.IsNan: - EvaluateFPUnary(operation, (x) => float.IsNaN(x)); - break; - - case Instruction.LoadConstant: - operation.TurnIntoCopy(Cbuf(operation.GetSource(0).Value, operation.GetSource(1).Value)); - break; - - case Instruction.Maximum: - EvaluateBinary(operation, (x, y) => Math.Max(x, y)); - break; - - case Instruction.MaximumU32: - EvaluateBinary(operation, (x, y) => (int)Math.Max((uint)x, (uint)y)); - break; - - case Instruction.Minimum: - EvaluateBinary(operation, (x, y) => Math.Min(x, y)); - break; - - case Instruction.MinimumU32: - EvaluateBinary(operation, (x, y) => (int)Math.Min((uint)x, (uint)y)); - break; - - case Instruction.Multiply: - EvaluateBinary(operation, (x, y) => x * y); - break; - - case Instruction.Negate: - EvaluateUnary(operation, (x) => -x); - break; - - case Instruction.ShiftLeft: - EvaluateBinary(operation, (x, y) => x << y); - break; - - case Instruction.ShiftRightS32: - EvaluateBinary(operation, (x, y) => x >> y); - break; - - case Instruction.ShiftRightU32: - EvaluateBinary(operation, (x, y) => (int)((uint)x >> y)); - break; - - case Instruction.Subtract: - EvaluateBinary(operation, (x, y) => x - y); - break; - - case Instruction.UnpackHalf2x16: - UnpackHalf2x16(operation); - break; - } - } - - private static bool AreAllSourcesConstant(Operation operation) - { - for (int index = 0; index < operation.SourcesCount; index++) - { - if (operation.GetSource(index).Type != OperandType.Constant) - { - return false; - } - } - - return true; - } - - private static int BitCount(int value) - { - int count = 0; - - for (int bit = 0; bit < 32; bit++) - { - if (value.Extract(bit)) - { - count++; - } - } - - return count; - } - - private static void BitfieldExtractS32(Operation operation) - { - int value = GetBitfieldExtractValue(operation); - - int shift = 32 - operation.GetSource(2).Value; - - value = (value << shift) >> shift; - - operation.TurnIntoCopy(Const(value)); - } - - private static void BitfieldExtractU32(Operation operation) - { - operation.TurnIntoCopy(Const(GetBitfieldExtractValue(operation))); - } - - private static int GetBitfieldExtractValue(Operation operation) - { - int value = operation.GetSource(0).Value; - int lsb = operation.GetSource(1).Value; - int length = operation.GetSource(2).Value; - - return value.Extract(lsb, length); - } - - private static void UnpackHalf2x16(Operation operation) - { - int value = operation.GetSource(0).Value; - - value = (value >> operation.Index * 16) & 0xffff; - - operation.TurnIntoCopy(ConstF((float)BitConverter.UInt16BitsToHalf((ushort)value))); - } - - private static void FPNegate(Operation operation) - { - float value = operation.GetSource(0).AsFloat(); - - operation.TurnIntoCopy(ConstF(-value)); - } - - private static void EvaluateUnary(Operation operation, Func<int, int> op) - { - int x = operation.GetSource(0).Value; - - operation.TurnIntoCopy(Const(op(x))); - } - - private static void EvaluateFPUnary(Operation operation, Func<float, float> op) - { - float x = operation.GetSource(0).AsFloat(); - - operation.TurnIntoCopy(ConstF(op(x))); - } - - private static void EvaluateFPUnary(Operation operation, Func<float, bool> op) - { - float x = operation.GetSource(0).AsFloat(); - - operation.TurnIntoCopy(Const(op(x) ? IrConsts.True : IrConsts.False)); - } - - private static void EvaluateBinary(Operation operation, Func<int, int, int> op) - { - int x = operation.GetSource(0).Value; - int y = operation.GetSource(1).Value; - - operation.TurnIntoCopy(Const(op(x, y))); - } - - private static void EvaluateBinary(Operation operation, Func<int, int, bool> op) - { - int x = operation.GetSource(0).Value; - int y = operation.GetSource(1).Value; - - operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); - } - - private static void EvaluateFPBinary(Operation operation, Func<float, float, float> op) - { - float x = operation.GetSource(0).AsFloat(); - float y = operation.GetSource(1).AsFloat(); - - operation.TurnIntoCopy(ConstF(op(x, y))); - } - - private static void EvaluateFPBinary(Operation operation, Func<float, float, bool> op) - { - float x = operation.GetSource(0).AsFloat(); - float y = operation.GetSource(1).AsFloat(); - - operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); - } - - private static void EvaluateTernary(Operation operation, Func<int, int, int, int> op) - { - int x = operation.GetSource(0).Value; - int y = operation.GetSource(1).Value; - int z = operation.GetSource(2).Value; - - operation.TurnIntoCopy(Const(op(x, y, z))); - } - - private static void EvaluateFPTernary(Operation operation, Func<float, float, float, float> op) - { - float x = operation.GetSource(0).AsFloat(); - float y = operation.GetSource(1).AsFloat(); - float z = operation.GetSource(2).AsFloat(); - - operation.TurnIntoCopy(ConstF(op(x, y, z))); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs deleted file mode 100644 index 2a4070e0..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs +++ /dev/null @@ -1,433 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System.Collections.Generic; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; -using static Ryujinx.Graphics.Shader.Translation.GlobalMemory; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class GlobalToStorage - { - public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask, ref int ubeUseMask) - { - int sbStart = GetStorageBaseCbOffset(config.Stage); - int sbEnd = sbStart + StorageDescsSize; - - int ubeStart = UbeBaseOffset; - int ubeEnd = UbeBaseOffset + UbeDescsSize; - - for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next) - { - for (int index = 0; index < node.Value.SourcesCount; index++) - { - Operand src = node.Value.GetSource(index); - - int storageIndex = GetStorageIndex(src, sbStart, sbEnd); - - if (storageIndex >= 0) - { - sbUseMask |= 1 << storageIndex; - } - - if (config.Stage == ShaderStage.Compute) - { - int constantIndex = GetStorageIndex(src, ubeStart, ubeEnd); - - if (constantIndex >= 0) - { - ubeUseMask |= 1 << constantIndex; - } - } - } - - if (!(node.Value is Operation operation)) - { - continue; - } - - if (UsesGlobalMemory(operation.Inst, operation.StorageKind)) - { - Operand source = operation.GetSource(0); - - int storageIndex = SearchForStorageBase(block, source, sbStart, sbEnd); - - if (storageIndex >= 0) - { - // Storage buffers are implemented using global memory access. - // If we know from where the base address of the access is loaded, - // we can guess which storage buffer it is accessing. - // We can then replace the global memory access with a storage - // buffer access. - node = ReplaceGlobalWithStorage(block, node, config, storageIndex); - } - else if (config.Stage == ShaderStage.Compute && operation.Inst == Instruction.LoadGlobal) - { - // Here we effectively try to replace a LDG instruction with LDC. - // The hardware only supports a limited amount of constant buffers - // so NVN "emulates" more constant buffers using global memory access. - // Here we try to replace the global access back to a constant buffer - // load. - storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd); - - if (storageIndex >= 0) - { - node = ReplaceLdgWithLdc(node, config, storageIndex); - } - } - } - } - - config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask); - } - - private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex) - { - Operation operation = (Operation)node.Value; - - bool isAtomic = operation.Inst.IsAtomic(); - bool isStg16Or8 = operation.Inst == Instruction.StoreGlobal16 || operation.Inst == Instruction.StoreGlobal8; - bool isWrite = isAtomic || operation.Inst == Instruction.StoreGlobal || isStg16Or8; - - config.SetUsedStorageBuffer(storageIndex, isWrite); - - Operand[] sources = new Operand[operation.SourcesCount]; - - sources[0] = Const(storageIndex); - sources[1] = GetStorageOffset(block, node, config, storageIndex, operation.GetSource(0), isStg16Or8); - - for (int index = 2; index < operation.SourcesCount; index++) - { - sources[index] = operation.GetSource(index); - } - - Operation storageOp; - - if (isAtomic) - { - storageOp = new Operation(operation.Inst, StorageKind.StorageBuffer, operation.Dest, sources); - } - else if (operation.Inst == Instruction.LoadGlobal) - { - storageOp = new Operation(Instruction.LoadStorage, operation.Dest, sources); - } - else - { - Instruction storeInst = operation.Inst switch - { - Instruction.StoreGlobal16 => Instruction.StoreStorage16, - Instruction.StoreGlobal8 => Instruction.StoreStorage8, - _ => Instruction.StoreStorage - }; - - storageOp = new Operation(storeInst, null, sources); - } - - for (int index = 0; index < operation.SourcesCount; index++) - { - operation.SetSource(index, null); - } - - LinkedListNode<INode> oldNode = node; - - node = node.List.AddBefore(node, storageOp); - - node.List.Remove(oldNode); - - return node; - } - - private static Operand GetStorageOffset( - BasicBlock block, - LinkedListNode<INode> node, - ShaderConfig config, - int storageIndex, - Operand addrLow, - bool isStg16Or8) - { - int baseAddressCbOffset = GetStorageCbOffset(config.Stage, storageIndex); - - bool storageAligned = !(config.GpuAccessor.QueryHasUnalignedStorageBuffer() || config.GpuAccessor.QueryHostStorageBufferOffsetAlignment() > Constants.StorageAlignment); - - (Operand byteOffset, int constantOffset) = storageAligned ? - GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) : - (null, 0); - - if (byteOffset != null) - { - ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset); - } - - if (byteOffset == null) - { - Operand baseAddrLow = Cbuf(0, baseAddressCbOffset); - Operand baseAddrTrunc = Local(); - - Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment()); - - Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask); - - node.List.AddBefore(node, andOp); - - Operand offset = Local(); - Operation subOp = new Operation(Instruction.Subtract, offset, addrLow, baseAddrTrunc); - - node.List.AddBefore(node, subOp); - - byteOffset = offset; - } - else if (constantOffset != 0) - { - Operand offset = Local(); - Operation addOp = new Operation(Instruction.Add, offset, byteOffset, Const(constantOffset)); - - node.List.AddBefore(node, addOp); - - byteOffset = offset; - } - - if (isStg16Or8) - { - return byteOffset; - } - - Operand wordOffset = Local(); - Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2)); - - node.List.AddBefore(node, shrOp); - - return wordOffset; - } - - private static bool IsCb0Offset(Operand operand, int offset) - { - return operand.Type == OperandType.ConstantBuffer && operand.GetCbufSlot() == 0 && operand.GetCbufOffset() == offset; - } - - private static void ReplaceAddressAlignment(LinkedList<INode> list, Operand address, Operand byteOffset, int constantOffset) - { - // When we emit 16/8-bit LDG, we add extra code to determine the address alignment. - // Eliminate the storage buffer base address from this too, leaving only the byte offset. - - foreach (INode useNode in address.UseOps) - { - if (useNode is Operation op && op.Inst == Instruction.BitwiseAnd) - { - Operand src1 = op.GetSource(0); - Operand src2 = op.GetSource(1); - - int addressIndex = -1; - - if (src1 == address && src2.Type == OperandType.Constant && src2.Value == 3) - { - addressIndex = 0; - } - else if (src2 == address && src1.Type == OperandType.Constant && src1.Value == 3) - { - addressIndex = 1; - } - - if (addressIndex != -1) - { - LinkedListNode<INode> node = list.Find(op); - - // Add offset calculation before the use. Needs to be on the same block. - if (node != null) - { - Operand offset = Local(); - Operation addOp = new Operation(Instruction.Add, offset, byteOffset, Const(constantOffset)); - list.AddBefore(node, addOp); - - op.SetSource(addressIndex, offset); - } - } - } - } - } - - private static (Operand, int) GetStorageOffset(BasicBlock block, Operand address, int baseAddressCbOffset) - { - if (IsCb0Offset(address, baseAddressCbOffset)) - { - // Direct offset: zero. - return (Const(0), 0); - } - - (address, int constantOffset) = GetStorageConstantOffset(block, address); - - address = Utils.FindLastOperation(address, block); - - if (IsCb0Offset(address, baseAddressCbOffset)) - { - // Only constant offset - return (Const(0), constantOffset); - } - - if (!(address.AsgOp is Operation offsetAdd) || offsetAdd.Inst != Instruction.Add) - { - return (null, 0); - } - - Operand src1 = offsetAdd.GetSource(0); - Operand src2 = Utils.FindLastOperation(offsetAdd.GetSource(1), block); - - if (IsCb0Offset(src2, baseAddressCbOffset)) - { - return (src1, constantOffset); - } - else if (IsCb0Offset(src1, baseAddressCbOffset)) - { - return (src2, constantOffset); - } - - return (null, 0); - } - - private static (Operand, int) GetStorageConstantOffset(BasicBlock block, Operand address) - { - if (!(address.AsgOp is Operation offsetAdd) || offsetAdd.Inst != Instruction.Add) - { - return (address, 0); - } - - Operand src1 = offsetAdd.GetSource(0); - Operand src2 = offsetAdd.GetSource(1); - - if (src2.Type != OperandType.Constant) - { - return (address, 0); - } - - return (src1, src2.Value); - } - - private static LinkedListNode<INode> ReplaceLdgWithLdc(LinkedListNode<INode> node, ShaderConfig config, int storageIndex) - { - Operation operation = (Operation)node.Value; - - Operand GetCbufOffset() - { - Operand addrLow = operation.GetSource(0); - - Operand baseAddrLow = Cbuf(0, UbeBaseOffset + storageIndex * StorageDescSize); - - Operand baseAddrTrunc = Local(); - - Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment()); - - Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask); - - node.List.AddBefore(node, andOp); - - Operand byteOffset = Local(); - Operand wordOffset = Local(); - - Operation subOp = new Operation(Instruction.Subtract, byteOffset, addrLow, baseAddrTrunc); - Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2)); - - node.List.AddBefore(node, subOp); - node.List.AddBefore(node, shrOp); - - return wordOffset; - } - - Operand[] sources = new Operand[operation.SourcesCount]; - - int cbSlot = UbeFirstCbuf + storageIndex; - - sources[0] = Const(cbSlot); - sources[1] = GetCbufOffset(); - - config.SetUsedConstantBuffer(cbSlot); - - for (int index = 2; index < operation.SourcesCount; index++) - { - sources[index] = operation.GetSource(index); - } - - Operation ldcOp = new Operation(Instruction.LoadConstant, operation.Dest, sources); - - for (int index = 0; index < operation.SourcesCount; index++) - { - operation.SetSource(index, null); - } - - LinkedListNode<INode> oldNode = node; - - node = node.List.AddBefore(node, ldcOp); - - node.List.Remove(oldNode); - - return node; - } - - private static int SearchForStorageBase(BasicBlock block, Operand globalAddress, int sbStart, int sbEnd) - { - globalAddress = Utils.FindLastOperation(globalAddress, block); - - if (globalAddress.Type == OperandType.ConstantBuffer) - { - return GetStorageIndex(globalAddress, sbStart, sbEnd); - } - - Operation operation = globalAddress.AsgOp as Operation; - - if (operation == null || operation.Inst != Instruction.Add) - { - return -1; - } - - Operand src1 = operation.GetSource(0); - Operand src2 = operation.GetSource(1); - - if ((src1.Type == OperandType.LocalVariable && src2.Type == OperandType.Constant) || - (src2.Type == OperandType.LocalVariable && src1.Type == OperandType.Constant)) - { - if (src1.Type == OperandType.LocalVariable) - { - operation = Utils.FindLastOperation(src1, block).AsgOp as Operation; - } - else - { - operation = Utils.FindLastOperation(src2, block).AsgOp as Operation; - } - - if (operation == null || operation.Inst != Instruction.Add) - { - return -1; - } - } - - for (int index = 0; index < operation.SourcesCount; index++) - { - Operand source = operation.GetSource(index); - - int storageIndex = GetStorageIndex(source, sbStart, sbEnd); - - if (storageIndex != -1) - { - return storageIndex; - } - } - - return -1; - } - - private static int GetStorageIndex(Operand operand, int sbStart, int sbEnd) - { - if (operand.Type == OperandType.ConstantBuffer) - { - int slot = operand.GetCbufSlot(); - int offset = operand.GetCbufOffset(); - - if (slot == 0 && offset >= sbStart && offset < sbEnd) - { - int storageIndex = (offset - sbStart) / StorageDescSize; - - return storageIndex; - } - } - - return -1; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs deleted file mode 100644 index bae774ee..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ /dev/null @@ -1,380 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class Optimizer - { - public static void RunPass(BasicBlock[] blocks, ShaderConfig config) - { - RunOptimizationPasses(blocks); - - int sbUseMask = 0; - int ubeUseMask = 0; - - // Those passes are looking for specific patterns and only needs to run once. - for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) - { - GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask); - BindlessToIndexed.RunPass(blocks[blkIndex], config); - BindlessElimination.RunPass(blocks[blkIndex], config); - } - - config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask); - - // Run optimizations one last time to remove any code that is now optimizable after above passes. - RunOptimizationPasses(blocks); - } - - private static void RunOptimizationPasses(BasicBlock[] blocks) - { - bool modified; - - do - { - modified = false; - - for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) - { - BasicBlock block = blocks[blkIndex]; - - LinkedListNode<INode> node = block.Operations.First; - - while (node != null) - { - LinkedListNode<INode> nextNode = node.Next; - - bool isUnused = IsUnused(node.Value); - - if (!(node.Value is Operation operation) || isUnused) - { - if (node.Value is PhiNode phi && !isUnused) - { - isUnused = PropagatePhi(phi); - } - - if (isUnused) - { - RemoveNode(block, node); - - modified = true; - } - - node = nextNode; - - continue; - } - - ConstantFolding.RunPass(operation); - - Simplification.RunPass(operation); - - if (DestIsLocalVar(operation)) - { - if (operation.Inst == Instruction.Copy) - { - PropagateCopy(operation); - - RemoveNode(block, node); - - modified = true; - } - else if ((operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) || - (operation.Inst == Instruction.ShuffleXor && MatchDdxOrDdy(operation))) - { - if (DestHasNoUses(operation)) - { - RemoveNode(block, node); - } - - modified = true; - } - } - - node = nextNode; - } - - if (BranchElimination.RunPass(block)) - { - RemoveNode(block, block.Operations.Last); - - modified = true; - } - } - } - while (modified); - } - - private static void PropagateCopy(Operation copyOp) - { - // Propagate copy source operand to all uses of - // the destination operand. - - Operand dest = copyOp.Dest; - Operand src = copyOp.GetSource(0); - - INode[] uses = dest.UseOps.ToArray(); - - foreach (INode useNode in uses) - { - for (int index = 0; index < useNode.SourcesCount; index++) - { - if (useNode.GetSource(index) == dest) - { - useNode.SetSource(index, src); - } - } - } - } - - private static bool PropagatePhi(PhiNode phi) - { - // If all phi sources are the same, we can propagate it and remove the phi. - - Operand firstSrc = phi.GetSource(0); - - for (int index = 1; index < phi.SourcesCount; index++) - { - if (!IsSameOperand(firstSrc, phi.GetSource(index))) - { - return false; - } - } - - // All sources are equal, we can propagate the value. - - Operand dest = phi.Dest; - - INode[] uses = dest.UseOps.ToArray(); - - foreach (INode useNode in uses) - { - for (int index = 0; index < useNode.SourcesCount; index++) - { - if (useNode.GetSource(index) == dest) - { - useNode.SetSource(index, firstSrc); - } - } - } - - return true; - } - - private static bool IsSameOperand(Operand x, Operand y) - { - if (x.Type != y.Type || x.Value != y.Value) - { - return false; - } - - // TODO: Handle Load operations with the same storage and the same constant parameters. - return x.Type == OperandType.Constant || x.Type == OperandType.ConstantBuffer; - } - - private static bool PropagatePack(Operation packOp) - { - // Propagate pack source operands to uses by unpack - // instruction. The source depends on the unpack instruction. - bool modified = false; - - Operand dest = packOp.Dest; - Operand src0 = packOp.GetSource(0); - Operand src1 = packOp.GetSource(1); - - INode[] uses = dest.UseOps.ToArray(); - - foreach (INode useNode in uses) - { - if (!(useNode is Operation operation) || operation.Inst != Instruction.UnpackHalf2x16) - { - continue; - } - - if (operation.GetSource(0) == dest) - { - operation.TurnIntoCopy(operation.Index == 1 ? src1 : src0); - - modified = true; - } - } - - return modified; - } - - public static bool MatchDdxOrDdy(Operation operation) - { - // It's assumed that "operation.Inst" is ShuffleXor, - // that should be checked before calling this method. - Debug.Assert(operation.Inst == Instruction.ShuffleXor); - - bool modified = false; - - Operand src2 = operation.GetSource(1); - Operand src3 = operation.GetSource(2); - - if (src2.Type != OperandType.Constant || (src2.Value != 1 && src2.Value != 2)) - { - return false; - } - - if (src3.Type != OperandType.Constant || src3.Value != 0x1c03) - { - return false; - } - - bool isDdy = src2.Value == 2; - bool isDdx = !isDdy; - - // We can replace any use by a FSWZADD with DDX/DDY, when - // the following conditions are true: - // - The mask should be 0b10100101 for DDY, or 0b10011001 for DDX. - // - The first source operand must be the shuffle output. - // - The second source operand must be the shuffle first source operand. - INode[] uses = operation.Dest.UseOps.ToArray(); - - foreach (INode use in uses) - { - if (!(use is Operation test)) - { - continue; - } - - if (!(use is Operation useOp) || useOp.Inst != Instruction.SwizzleAdd) - { - continue; - } - - Operand fswzaddSrc1 = useOp.GetSource(0); - Operand fswzaddSrc2 = useOp.GetSource(1); - Operand fswzaddSrc3 = useOp.GetSource(2); - - if (fswzaddSrc1 != operation.Dest) - { - continue; - } - - if (fswzaddSrc2 != operation.GetSource(0)) - { - continue; - } - - if (fswzaddSrc3.Type != OperandType.Constant) - { - continue; - } - - int mask = fswzaddSrc3.Value; - - if ((isDdx && mask != 0b10011001) || - (isDdy && mask != 0b10100101)) - { - continue; - } - - useOp.TurnInto(isDdx ? Instruction.Ddx : Instruction.Ddy, fswzaddSrc2); - - modified = true; - } - - return modified; - } - - private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode) - { - // Remove a node from the nodes list, and also remove itself - // from all the use lists on the operands that this node uses. - block.Operations.Remove(llNode); - - Queue<INode> nodes = new Queue<INode>(); - - nodes.Enqueue(llNode.Value); - - while (nodes.TryDequeue(out INode node)) - { - for (int index = 0; index < node.SourcesCount; index++) - { - Operand src = node.GetSource(index); - - if (src.Type != OperandType.LocalVariable) - { - continue; - } - - if (src.UseOps.Remove(node) && src.UseOps.Count == 0) - { - Debug.Assert(src.AsgOp != null); - nodes.Enqueue(src.AsgOp); - } - } - } - } - - private static bool IsUnused(INode node) - { - return !HasSideEffects(node) && DestIsLocalVar(node) && DestHasNoUses(node); - } - - private static bool HasSideEffects(INode node) - { - if (node is Operation operation) - { - switch (operation.Inst & Instruction.Mask) - { - case Instruction.AtomicAdd: - case Instruction.AtomicAnd: - case Instruction.AtomicCompareAndSwap: - case Instruction.AtomicMaxS32: - case Instruction.AtomicMaxU32: - case Instruction.AtomicMinS32: - case Instruction.AtomicMinU32: - case Instruction.AtomicOr: - case Instruction.AtomicSwap: - case Instruction.AtomicXor: - case Instruction.Call: - case Instruction.ImageAtomic: - return true; - } - } - - return false; - } - - private static bool DestIsLocalVar(INode node) - { - if (node.DestsCount == 0) - { - return false; - } - - for (int index = 0; index < node.DestsCount; index++) - { - Operand dest = node.GetDest(index); - - if (dest != null && dest.Type != OperandType.LocalVariable) - { - return false; - } - } - - return true; - } - - private static bool DestHasNoUses(INode node) - { - for (int index = 0; index < node.DestsCount; index++) - { - Operand dest = node.GetDest(index); - - if (dest != null && dest.UseOps.Count != 0) - { - return false; - } - } - - return true; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs deleted file mode 100644 index 8d05f99a..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Simplification.cs +++ /dev/null @@ -1,147 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; - -using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class Simplification - { - private const int AllOnes = ~0; - - public static void RunPass(Operation operation) - { - switch (operation.Inst) - { - case Instruction.Add: - case Instruction.BitwiseExclusiveOr: - TryEliminateBinaryOpCommutative(operation, 0); - break; - - case Instruction.BitwiseAnd: - TryEliminateBitwiseAnd(operation); - break; - - case Instruction.BitwiseOr: - TryEliminateBitwiseOr(operation); - break; - - case Instruction.ConditionalSelect: - TryEliminateConditionalSelect(operation); - break; - - case Instruction.Divide: - TryEliminateBinaryOpY(operation, 1); - break; - - case Instruction.Multiply: - TryEliminateBinaryOpCommutative(operation, 1); - break; - - case Instruction.ShiftLeft: - case Instruction.ShiftRightS32: - case Instruction.ShiftRightU32: - case Instruction.Subtract: - TryEliminateBinaryOpY(operation, 0); - break; - } - } - - private static void TryEliminateBitwiseAnd(Operation operation) - { - // Try to recognize and optimize those 3 patterns (in order): - // x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y, - // x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000 - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, AllOnes)) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, AllOnes)) - { - operation.TurnIntoCopy(x); - } - else if (IsConstEqual(x, 0) || IsConstEqual(y, 0)) - { - operation.TurnIntoCopy(Const(0)); - } - } - - private static void TryEliminateBitwiseOr(Operation operation) - { - // Try to recognize and optimize those 3 patterns (in order): - // x | 0x00000000 == x, 0x00000000 | y == y, - // x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, 0)) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, 0)) - { - operation.TurnIntoCopy(x); - } - else if (IsConstEqual(x, AllOnes) || IsConstEqual(y, AllOnes)) - { - operation.TurnIntoCopy(Const(AllOnes)); - } - } - - private static void TryEliminateBinaryOpY(Operation operation, int comparand) - { - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(y, comparand)) - { - operation.TurnIntoCopy(x); - } - } - - private static void TryEliminateBinaryOpCommutative(Operation operation, int comparand) - { - Operand x = operation.GetSource(0); - Operand y = operation.GetSource(1); - - if (IsConstEqual(x, comparand)) - { - operation.TurnIntoCopy(y); - } - else if (IsConstEqual(y, comparand)) - { - operation.TurnIntoCopy(x); - } - } - - private static void TryEliminateConditionalSelect(Operation operation) - { - Operand cond = operation.GetSource(0); - - if (cond.Type != OperandType.Constant) - { - return; - } - - // The condition is constant, we can turn it into a copy, and select - // the source based on the condition value. - int srcIndex = cond.Value != 0 ? 1 : 2; - - Operand source = operation.GetSource(srcIndex); - - operation.TurnIntoCopy(source); - } - - private static bool IsConstEqual(Operand operand, int comparand) - { - if (operand.Type != OperandType.Constant) - { - return false; - } - - return operand.Value == comparand; - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs deleted file mode 100644 index 4ca6d687..00000000 --- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Utils.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Ryujinx.Graphics.Shader.IntermediateRepresentation; - -namespace Ryujinx.Graphics.Shader.Translation.Optimizations -{ - static class Utils - { - private static Operation FindBranchSource(BasicBlock block) - { - foreach (BasicBlock sourceBlock in block.Predecessors) - { - if (sourceBlock.Operations.Count > 0) - { - if (sourceBlock.GetLastOp() is Operation lastOp && IsConditionalBranch(lastOp.Inst) && sourceBlock.Next == block) - { - return lastOp; - } - } - } - - return null; - } - - private static bool IsConditionalBranch(Instruction inst) - { - return inst == Instruction.BranchIfFalse || inst == Instruction.BranchIfTrue; - } - - private static bool BlockConditionsMatch(BasicBlock currentBlock, BasicBlock queryBlock) - { - // Check if all the conditions for the query block are satisfied by the current block. - // Just checks the top-most conditional for now. - - Operation currentBranch = FindBranchSource(currentBlock); - Operation queryBranch = FindBranchSource(queryBlock); - - Operand currentCondition = currentBranch?.GetSource(0); - Operand queryCondition = queryBranch?.GetSource(0); - - // The condition should be the same operand instance. - - return currentBranch != null && queryBranch != null && - currentBranch.Inst == queryBranch.Inst && - currentCondition == queryCondition; - } - - public static Operand FindLastOperation(Operand source, BasicBlock block) - { - if (source.AsgOp is PhiNode phiNode) - { - // This source can have a different value depending on a previous branch. - // Ensure that conditions met for that branch are also met for the current one. - // Prefer the latest sources for the phi node. - - for (int i = phiNode.SourcesCount - 1; i >= 0; i--) - { - BasicBlock phiBlock = phiNode.GetBlock(i); - - if (BlockConditionsMatch(block, phiBlock)) - { - return phiNode.GetSource(i); - } - } - } - - return source; - } - } -} |
