diff --git a/Ryujinx.Graphics.GAL/Capabilities.cs b/Ryujinx.Graphics.GAL/Capabilities.cs
index 6e5329b2ae..20bd87c6c8 100644
--- a/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.GAL
         public bool HasVectorIndexingBug { get; }
 
         public bool SupportsAstcCompression { get; }
+        public bool SupportsFragmentShaderInterlock { get; }
+        public bool SupportsFragmentShaderOrderingIntel { get; }
         public bool SupportsImageLoadFormatted { get; }
         public bool SupportsMismatchingViewFormat { get; }
         public bool SupportsNonConstantTextureOffset { get; }
@@ -22,6 +24,8 @@ namespace Ryujinx.Graphics.GAL
             bool hasFrontFacingBug,
             bool hasVectorIndexingBug,
             bool supportsAstcCompression,
+            bool supportsFragmentShaderInterlock,
+            bool supportsFragmentShaderOrderingIntel,
             bool supportsImageLoadFormatted,
             bool supportsMismatchingViewFormat,
             bool supportsNonConstantTextureOffset,
@@ -36,6 +40,8 @@ namespace Ryujinx.Graphics.GAL
             HasFrontFacingBug = hasFrontFacingBug;
             HasVectorIndexingBug = hasVectorIndexingBug;
             SupportsAstcCompression = supportsAstcCompression;
+            SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
+            SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
             SupportsImageLoadFormatted = supportsImageLoadFormatted;
             SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
             SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 619a8c5f4f..be5e7ab90d 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <summary>
         /// Version of the codegen (to be changed when codegen or guest format change).
         /// </summary>
-        private const ulong ShaderCodeGenVersion = 2741;
+        private const ulong ShaderCodeGenVersion = 2768;
 
         // Progress reporting helpers
         private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
index 40353850fb..50039a90ac 100644
--- a/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs
@@ -36,6 +36,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <returns>Host storage buffer alignment in bytes</returns>
         public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
 
+        /// <summary>
+        /// Queries host support for fragment shader ordering critical sections on the shader code.
+        /// </summary>
+        /// <returns>True if fragment shader interlock is supported, false otherwise</returns>
+        public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
+
+        /// <summary>
+        /// Queries host support for fragment shader ordering scoped critical sections on the shader code.
+        /// </summary>
+        /// <returns>True if fragment shader ordering is supported, false otherwise</returns>
+        public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
+
         /// <summary>
         /// Queries host support for readable images without a explicit format declaration on the shader.
         /// </summary>
diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
index 9a62bb2ec4..ec9bd4a201 100644
--- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
+++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs
@@ -6,7 +6,10 @@ namespace Ryujinx.Graphics.OpenGL
     static class HwCapabilities
     {
         private static readonly Lazy<bool> _supportsAstcCompression           = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
+        private static readonly Lazy<bool> _supportsFragmentShaderInterlock   = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
+        private static readonly Lazy<bool> _supportsFragmentShaderOrdering    = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
         private static readonly Lazy<bool> _supportsImageLoadFormatted        = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
+        private static readonly Lazy<bool> _supportsIndirectParameters        = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
         private static readonly Lazy<bool> _supportsParallelShaderCompile     = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
         private static readonly Lazy<bool> _supportsPolygonOffsetClamp        = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
         private static readonly Lazy<bool> _supportsQuads                     = new Lazy<bool>(SupportsQuadsCheck);
@@ -14,7 +17,6 @@ namespace Ryujinx.Graphics.OpenGL
         private static readonly Lazy<bool> _supportsShaderBallot              = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
         private static readonly Lazy<bool> _supportsTextureShadowLod          = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
         private static readonly Lazy<bool> _supportsViewportSwizzle           = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
-        private static readonly Lazy<bool> _supportsIndirectParameters        = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
 
         private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
         private static readonly Lazy<int> _storageBufferOffsetAlignment   = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
@@ -41,7 +43,10 @@ namespace Ryujinx.Graphics.OpenGL
         public static bool UsePersistentBufferForFlush       => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
 
         public static bool SupportsAstcCompression           => _supportsAstcCompression.Value;
+        public static bool SupportsFragmentShaderInterlock   => _supportsFragmentShaderInterlock.Value;
+        public static bool SupportsFragmentShaderOrdering    => _supportsFragmentShaderOrdering.Value;
         public static bool SupportsImageLoadFormatted        => _supportsImageLoadFormatted.Value;
+        public static bool SupportsIndirectParameters        => _supportsIndirectParameters.Value;
         public static bool SupportsParallelShaderCompile     => _supportsParallelShaderCompile.Value;
         public static bool SupportsPolygonOffsetClamp        => _supportsPolygonOffsetClamp.Value;
         public static bool SupportsQuads                     => _supportsQuads.Value;
@@ -49,7 +54,6 @@ namespace Ryujinx.Graphics.OpenGL
         public static bool SupportsShaderBallot              => _supportsShaderBallot.Value;
         public static bool SupportsTextureShadowLod          => _supportsTextureShadowLod.Value;
         public static bool SupportsViewportSwizzle           => _supportsViewportSwizzle.Value;
-        public static bool SupportsIndirectParameters        => _supportsIndirectParameters.Value;
 
         public static bool SupportsMismatchingViewFormat    => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
         public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 768c7450cb..25b762b2af 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -104,6 +104,8 @@ namespace Ryujinx.Graphics.OpenGL
                 HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows,
                 HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows,
                 HwCapabilities.SupportsAstcCompression,
+                HwCapabilities.SupportsFragmentShaderInterlock,
+                HwCapabilities.SupportsFragmentShaderOrdering,
                 HwCapabilities.SupportsImageLoadFormatted,
                 HwCapabilities.SupportsMismatchingViewFormat,
                 HwCapabilities.SupportsNonConstantTextureOffset,
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 85288afac3..7dcd1671ea 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -32,6 +32,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             {
                 context.AppendLine("#extension GL_ARB_compute_shader : enable");
             }
+            else if (context.Config.Stage == ShaderStage.Fragment)
+            {
+                if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
+                {
+                    context.AppendLine("#extension GL_ARB_fragment_shader_interlock : enable");
+                }
+                else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel())
+                {
+                    context.AppendLine("#extension GL_INTEL_fragment_shader_ordering : enable");
+                }
+            }
 
             if (context.Config.GpPassthrough)
             {
@@ -431,6 +442,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
                 string imageTypeName = descriptor.Type.ToGlslImageType(descriptor.Format.GetComponentType());
 
+                if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
+                {
+                    imageTypeName = "coherent " + imageTypeName;
+                }
+
                 string layout = descriptor.Format.ToGlslFormat();
 
                 if (!string.IsNullOrEmpty(layout))
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
index 077737c897..3af120f882 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs
@@ -117,7 +117,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
             {
                 if (node is AstOperation operation)
                 {
-                    context.AppendLine(InstGen.GetExpression(context, operation) + ";");
+                    string expr = InstGen.GetExpression(context, operation);
+
+                    if (expr != null)
+                    {
+                        context.AppendLine(expr + ";");
+                    }
                 }
                 else if (node is AstAssignment assignment)
                 {
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
index 4f0591499a..1acac74564 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
@@ -4,6 +4,7 @@ using System;
 
 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall;
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenFSI;
 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
 using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenPacking;
@@ -144,6 +145,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
                     case Instruction.Call:
                         return Call(context, operation);
 
+                    case Instruction.FSIBegin:
+                        return FSIBegin(context);
+
+                    case Instruction.FSIEnd:
+                        return FSIEnd(context);
+
                     case Instruction.ImageLoad:
                     case Instruction.ImageStore:
                     case Instruction.ImageAtomic:
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenFSI.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenFSI.cs
new file mode 100644
index 0000000000..f61a53cbe8
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenFSI.cs
@@ -0,0 +1,29 @@
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    static class InstGenFSI
+    {
+        public static string FSIBegin(CodeGenContext context)
+        {
+            if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
+            {
+                return "beginInvocationInterlockARB()";
+            }
+            else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel())
+            {
+                return "beginFragmentShaderOrderingINTEL()";
+            }
+
+            return null;
+        }
+
+        public static string FSIEnd(CodeGenContext context)
+        {
+            if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
+            {
+                return "endInvocationInterlockARB()";
+            }
+
+            return null;
+        }
+    }
+}
\ 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 c2d59ff722..1fa2539928 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
@@ -65,6 +65,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
             Add(Instruction.EmitVertex,               InstType.CallNullary,    "EmitVertex");
             Add(Instruction.EndPrimitive,             InstType.CallNullary,    "EndPrimitive");
             Add(Instruction.ExponentB2,               InstType.CallUnary,      "exp2");
+            Add(Instruction.FSIBegin,                 InstType.Special);
+            Add(Instruction.FSIEnd,                   InstType.Special);
             Add(Instruction.FindFirstSetS32,          InstType.CallUnary,      "findMSB");
             Add(Instruction.FindFirstSetU32,          InstType.CallUnary,      "findMSB");
             Add(Instruction.Floor,                    InstType.CallUnary,      "floor");
diff --git a/Ryujinx.Graphics.Shader/Decoders/DecodedFunction.cs b/Ryujinx.Graphics.Shader/Decoders/DecodedFunction.cs
new file mode 100644
index 0000000000..7a172fe6fb
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/DecodedFunction.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class DecodedFunction
+    {
+        private readonly HashSet<DecodedFunction> _callers;
+
+        public bool IsCompilerGenerated => Type != FunctionType.User;
+        public FunctionType Type { get; set; }
+        public int Id { get; set; }
+
+        public ulong Address { get; }
+        public Block[] Blocks { get; private set; }
+
+        public DecodedFunction(ulong address)
+        {
+            Address = address;
+            _callers = new HashSet<DecodedFunction>();
+            Type = FunctionType.User;
+            Id = -1;
+        }
+
+        public void SetBlocks(Block[] blocks)
+        {
+            if (Blocks != null)
+            {
+                throw new InvalidOperationException("Blocks have already been set.");
+            }
+
+            Blocks = blocks;
+        }
+
+        public void AddCaller(DecodedFunction caller)
+        {
+            _callers.Add(caller);
+        }
+
+        public void RemoveCaller(DecodedFunction caller)
+        {
+            if (_callers.Remove(caller) && _callers.Count == 0)
+            {
+                Type = FunctionType.Unused;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/DecodedProgram.cs b/Ryujinx.Graphics.Shader/Decoders/DecodedProgram.cs
new file mode 100644
index 0000000000..80de41d7ea
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/DecodedProgram.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    struct DecodedProgram : IEnumerable<DecodedFunction>
+    {
+        public DecodedFunction MainFunction { get; }
+        private readonly IReadOnlyDictionary<ulong, DecodedFunction> _functions;
+        private readonly List<DecodedFunction> _functionsWithId;
+        public int FunctionsWithIdCount => _functionsWithId.Count;
+
+        public DecodedProgram(DecodedFunction mainFunction, IReadOnlyDictionary<ulong, DecodedFunction> functions)
+        {
+            MainFunction = mainFunction;
+            _functions = functions;
+            _functionsWithId = new List<DecodedFunction>();
+        }
+
+        public DecodedFunction GetFunctionByAddress(ulong address)
+        {
+            if (_functions.TryGetValue(address, out DecodedFunction function))
+            {
+                return function;
+            }
+
+            return null;
+        }
+
+        public DecodedFunction GetFunctionById(int id)
+        {
+            if ((uint)id >= (uint)_functionsWithId.Count)
+            {
+                throw new ArgumentOutOfRangeException(nameof(id));
+            }
+
+            return _functionsWithId[id];
+        }
+
+        public void AddFunctionAndSetId(DecodedFunction function)
+        {
+            function.Id = _functionsWithId.Count;
+            _functionsWithId.Add(function);
+        }
+
+        public IEnumerator<DecodedFunction> GetEnumerator()
+        {
+            return _functions.Values.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index b446e65047..714aaad342 100644
--- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -10,24 +10,25 @@ namespace Ryujinx.Graphics.Shader.Decoders
 {
     static class Decoder
     {
-        public static Block[][] Decode(ShaderConfig config, ulong startAddress)
+        public static DecodedProgram Decode(ShaderConfig config, ulong startAddress)
         {
-            List<Block[]> funcs = new List<Block[]>();
+            Queue<DecodedFunction> functionsQueue = new Queue<DecodedFunction>();
+            Dictionary<ulong, DecodedFunction> functionsVisited = new Dictionary<ulong, DecodedFunction>();
 
-            Queue<ulong> funcQueue = new Queue<ulong>();
-            HashSet<ulong> funcVisited = new HashSet<ulong>();
-
-            void EnqueueFunction(ulong funcAddress)
+            DecodedFunction EnqueueFunction(ulong address)
             {
-                if (funcVisited.Add(funcAddress))
+                if (!functionsVisited.TryGetValue(address, out DecodedFunction function))
                 {
-                    funcQueue.Enqueue(funcAddress);
+                    functionsVisited.Add(address, function = new DecodedFunction(address));
+                    functionsQueue.Enqueue(function);
                 }
+
+                return function;
             }
 
-            funcQueue.Enqueue(0);
+            DecodedFunction mainFunction = EnqueueFunction(0);
 
-            while (funcQueue.TryDequeue(out ulong funcAddress))
+            while (functionsQueue.TryDequeue(out DecodedFunction currentFunction))
             {
                 List<Block> blocks = new List<Block>();
                 Queue<Block> workQueue = new Queue<Block>();
@@ -46,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
                     return block;
                 }
 
-                GetBlock(funcAddress);
+                GetBlock(currentFunction.Address);
 
                 bool hasNewTarget;
 
@@ -108,7 +109,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
 
                             if (lastOp.Name == InstName.Cal)
                             {
-                                EnqueueFunction(lastOp.GetAbsoluteAddress());
+                                EnqueueFunction(lastOp.GetAbsoluteAddress()).AddCaller(currentFunction);
                             }
                             else if (lastOp.Name == InstName.Bra)
                             {
@@ -157,10 +158,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
                 }
                 while (hasNewTarget);
 
-                funcs.Add(blocks.ToArray());
+                currentFunction.SetBlocks(blocks.ToArray());
             }
 
-            return funcs.ToArray();
+            return new DecodedProgram(mainFunction, functionsVisited);
         }
 
         private static bool BinarySearch(List<Block> blocks, ulong address, out int index)
diff --git a/Ryujinx.Graphics.Shader/Decoders/FunctionType.cs b/Ryujinx.Graphics.Shader/Decoders/FunctionType.cs
new file mode 100644
index 0000000000..6ea6a82aee
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Decoders/FunctionType.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum FunctionType : byte
+    {
+        User,
+        Unused,
+        BuiltInFSIBegin,
+        BuiltInFSIEnd
+    }
+}
diff --git a/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs b/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs
index b61412c6e3..397e327e1f 100644
--- a/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/InstDecoders.cs
@@ -404,13 +404,22 @@ namespace Ryujinx.Graphics.Shader.Decoders
         Attr = 3,
     }
 
-    enum CacheOp
+    enum CacheOpLd
     {
+        Ca = 0,
         Cg = 1,
         Ci = 2,
         Cv = 3,
     }
 
+    enum CacheOpSt
+    {
+        Wb = 0,
+        Cg = 1,
+        Ci = 2,
+        Wt = 3,
+    }
+
     enum LsSize
     {
         U8 = 0,
@@ -1163,19 +1172,19 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public CctltOp CctltOp => (CctltOp)((_opcode >> 0) & 0x3);
     }
 
-    struct InstContUnsup
+    struct InstCont
     {
         private ulong _opcode;
-        public InstContUnsup(ulong opcode) => _opcode = opcode;
+        public InstCont(ulong opcode) => _opcode = opcode;
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public Ccc Ccc => (Ccc)((_opcode >> 0) & 0x1F);
     }
 
-    struct InstCsetUnsup
+    struct InstCset
     {
         private ulong _opcode;
-        public InstCsetUnsup(ulong opcode) => _opcode = opcode;
+        public InstCset(ulong opcode) => _opcode = opcode;
         public int Dest => (int)((_opcode >> 0) & 0xFF);
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
@@ -3507,7 +3516,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public int SrcPred => (int)((_opcode >> 58) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 56) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 56) & 0x3);
         public LsSize LsSize => (LsSize)((_opcode >> 53) & 0x7);
         public bool E => (_opcode & 0x10000000000000) != 0;
         public int Imm32 => (int)(_opcode >> 20);
@@ -3536,7 +3545,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public LsSize LsSize => (LsSize)((_opcode >> 48) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 46) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 46) & 0x3);
         public bool E => (_opcode & 0x200000000000) != 0;
         public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
     }
@@ -4502,7 +4511,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public int SrcPred => (int)((_opcode >> 58) & 0x7);
-        public CacheOp Cop => (CacheOp)((_opcode >> 56) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 56) & 0x3);
         public LsSize LsSize => (LsSize)((_opcode >> 53) & 0x7);
         public bool E => (_opcode & 0x10000000000000) != 0;
         public int Imm32 => (int)(_opcode >> 20);
@@ -4517,7 +4526,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public LsSize2 LsSize => (LsSize2)((_opcode >> 48) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 46) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 46) & 0x3);
         public bool E => (_opcode & 0x200000000000) != 0;
         public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
     }
@@ -4531,7 +4540,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int Pred => (int)((_opcode >> 16) & 0x7);
         public bool PredInv => (_opcode & 0x80000) != 0;
         public LsSize2 LsSize => (LsSize2)((_opcode >> 48) & 0x7);
-        public CacheOp2 CacheOp => (CacheOp2)((_opcode >> 44) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 44) & 0x3);
         public int Imm24 => (int)((_opcode >> 20) & 0xFFFFFF);
     }
 
@@ -4653,7 +4662,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
         public int DestPred2 => (int)((_opcode >> 30) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
         public bool Ba => (_opcode & 0x800000) != 0;
         public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
     }
@@ -4670,7 +4679,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int TidB => (int)((_opcode >> 36) & 0x1FFF);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
         public int DestPred2 => (int)((_opcode >> 30) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
         public bool Ba => (_opcode & 0x800000) != 0;
         public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
     }
@@ -4687,7 +4696,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
         public int DestPred2 => (int)((_opcode >> 30) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
         public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
     }
 
@@ -4703,7 +4712,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public int TidB => (int)((_opcode >> 36) & 0x1FFF);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
         public int DestPred2 => (int)((_opcode >> 30) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpLd CacheOp => (CacheOpLd)((_opcode >> 24) & 0x3);
         public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
     }
 
@@ -4750,7 +4759,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public bool PredInv => (_opcode & 0x80000) != 0;
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
         public bool Ba => (_opcode & 0x800000) != 0;
         public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
     }
@@ -4766,7 +4775,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public int TidB => (int)((_opcode >> 36) & 0x1FFF);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
         public bool Ba => (_opcode & 0x800000) != 0;
         public SuSize Size => (SuSize)((_opcode >> 20) & 0x7);
     }
@@ -4782,7 +4791,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public bool PredInv => (_opcode & 0x80000) != 0;
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
         public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
     }
 
@@ -4797,7 +4806,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
         public Clamp Clamp => (Clamp)((_opcode >> 49) & 0x3);
         public int TidB => (int)((_opcode >> 36) & 0x1FFF);
         public SuDim Dim => (SuDim)((_opcode >> 33) & 0x7);
-        public CacheOp CacheOp => (CacheOp)((_opcode >> 24) & 0x3);
+        public CacheOpSt CacheOp => (CacheOpSt)((_opcode >> 24) & 0x3);
         public SuRgba Rgba => (SuRgba)((_opcode >> 20) & 0xF);
     }
 
diff --git a/Ryujinx.Graphics.Shader/Decoders/InstProps.cs b/Ryujinx.Graphics.Shader/Decoders/InstProps.cs
index 7d329a81e5..1af94ab593 100644
--- a/Ryujinx.Graphics.Shader/Decoders/InstProps.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/InstProps.cs
@@ -7,14 +7,22 @@ namespace Ryujinx.Graphics.Shader.Decoders
         Rd2 = 1 << 1,
         Ra = 1 << 2,
         Rb = 1 << 3,
-        Ib = 1 << 4,
-        Rc = 1 << 5,
-        Pd = 1 << 6,
-        Pd2 = 1 << 7,
-        Pdn = 1 << 8,
-        Tex = 1 << 9,
-        TexB = 1 << 10,
-        Bra = 1 << 11,
-        NoPred = 1 << 12
+        Rb2 = 1 << 4,
+        Ib = 1 << 5,
+        Rc = 1 << 6,
+
+        Pd = 1 << 7,
+        LPd = 2 << 7,
+        SPd = 3 << 7,
+        TPd = 4 << 7,
+        VPd = 5 << 7,
+        PdMask = 7 << 7,
+
+        Pdn = 1 << 10,
+        Ps = 1 << 11,
+        Tex = 1 << 12,
+        TexB = 1 << 13,
+        Bra = 1 << 14,
+        NoPred = 1 << 15
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Decoders/InstTable.cs b/Ryujinx.Graphics.Shader/Decoders/InstTable.cs
index c971d64686..2d91f21a08 100644
--- a/Ryujinx.Graphics.Shader/Decoders/InstTable.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/InstTable.cs
@@ -32,13 +32,13 @@ namespace Ryujinx.Graphics.Shader.Decoders
             #region Instructions
             Add("1110111110100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Al2p,        InstEmit.Al2p,        InstProps.Rd  | InstProps.Ra);
             Add("1110111111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ald,         InstEmit.Ald,         InstProps.Rd  | InstProps.Ra);
-            Add("1110111111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ast,         InstEmit.Ast,         InstProps.Ra  | InstProps.Rc);
+            Add("1110111111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ast,         InstEmit.Ast,         InstProps.Ra  | InstProps.Rb2 | InstProps.Rc);
             Add("11101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Atom,        InstEmit.Atom,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("111011101111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.AtomCas,     InstEmit.AtomCas,     InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("11101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Atoms,       InstEmit.Atoms,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("111011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.AtomsCas,    InstEmit.AtomsCas,    InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("1111000010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.B2r,         InstEmit.B2r,         InstProps.Rd  | InstProps.Ra);
-            Add("1111000010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bar,         InstEmit.Bar,         InstProps.Ra);
+            Add("1111000010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.B2r,         InstEmit.B2r,         InstProps.Rd  | InstProps.Ra  | InstProps.VPd);
+            Add("1111000010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bar,         InstEmit.Bar,         InstProps.Ra  | InstProps.Ps);
             Add("0101110000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe,         InstEmit.BfeR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x00000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe,         InstEmit.BfeI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bfe,         InstEmit.BfeC,        InstProps.Rd  | InstProps.Ra);
@@ -56,8 +56,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("1110101111110xx0000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cctlt,       InstEmit.Cctlt);
             Add("1110101111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cctlt,       InstEmit.Cctlt,       InstProps.Rc);
             Add("111000110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cont,        InstEmit.Cont);
-            Add("0101000010011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cset,        InstEmit.Cset,        InstProps.Rd);
-            Add("0101000010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Csetp,       InstEmit.Csetp,       InstProps.Pd  | InstProps.Pdn);
+            Add("0101000010011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cset,        InstEmit.Cset,        InstProps.Rd  | InstProps.Ps);
+            Add("0101000010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Csetp,       InstEmit.Csetp,       InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("0101000011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cs2r,        InstEmit.Cs2r,        InstProps.Rd);
             Add("0101110001110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dadd,        InstEmit.DaddR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x01110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dadd,        InstEmit.DaddI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
@@ -67,18 +67,18 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0011011x0111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma,        InstEmit.DfmaI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
             Add("010010110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma,        InstEmit.DfmaC,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
             Add("010100110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dfma,        InstEmit.DfmaRc,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
-            Add("0101110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011100x01010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("0100110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxC,      InstProps.Rd  | InstProps.Ra);
+            Add("0101110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011100x01010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("0100110001010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmnmx,       InstEmit.DmnmxC,      InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
             Add("0101110010000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul,        InstEmit.DmulR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x10000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul,        InstEmit.DmulI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110010000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dmul,        InstEmit.DmulC,       InstProps.Rd  | InstProps.Ra);
-            Add("010110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011001x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("010010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetC,       InstProps.Rd  | InstProps.Ra);
-            Add("010110111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn);
-            Add("0011011x1000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn);
-            Add("010010111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn);
+            Add("010110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011001x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("010010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dset,        InstEmit.DsetC,       InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
+            Add("010110111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("0011011x1000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("010010111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Dsetp,       InstEmit.DsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("111000110000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Exit,        InstEmit.Exit,        InstProps.Bra);
             Add("0101110010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.F2f,         InstEmit.F2fR,        InstProps.Rd  | InstProps.Rb);
             Add("0011100x10101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.F2f,         InstEmit.F2fI,        InstProps.Rd  | InstProps.Ib);
@@ -105,19 +105,19 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0101110000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo,         InstEmit.FloR,        InstProps.Rd  | InstProps.Rb);
             Add("0011100x00110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo,         InstEmit.FloI,        InstProps.Rd  | InstProps.Ib);
             Add("0100110000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Flo,         InstEmit.FloC,        InstProps.Rd);
-            Add("0101110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011100x01100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("0100110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxC,      InstProps.Rd  | InstProps.Ra);
+            Add("0101110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011100x01100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("0100110001100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmnmx,       InstEmit.FmnmxC,      InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
             Add("0101110001101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul,        InstEmit.FmulR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x01101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul,        InstEmit.FmulI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110001101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul,        InstEmit.FmulC,       InstProps.Rd  | InstProps.Ra);
             Add("00011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fmul32i,     InstEmit.Fmul32i,     InstProps.Rd  | InstProps.Ra);
-            Add("01011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("01001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetC,       InstProps.Rd  | InstProps.Ra);
-            Add("010110111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn);
-            Add("0011011x1011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn);
-            Add("010010111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn);
+            Add("01011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("01001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fset,        InstEmit.FsetC,       InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
+            Add("010110111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("0011011x1011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("010010111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fsetp,       InstEmit.FsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("0101000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Fswzadd,     InstEmit.Fswzadd,     InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("111000101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Getcrsptr,   InstEmit.Getcrsptr,   InstProps.Rd  | InstProps.NoPred);
             Add("111000101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Getlmembase, InstEmit.Getlmembase, InstProps.Rd  | InstProps.NoPred);
@@ -133,12 +133,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0111100x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul2,       InstEmit.Hmul2I,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0111100x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul2,       InstEmit.Hmul2C,      InstProps.Rd  | InstProps.Ra);
             Add("0010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hmul232i,    InstEmit.Hmul232i,    InstProps.Rd  | InstProps.Ra);
-            Add("0101110100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2R,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0111110x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2I,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("0111110x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2C,      InstProps.Rd  | InstProps.Ra);
-            Add("0101110100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2R,     InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn);
-            Add("0111111x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2I,     InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn);
-            Add("0111111x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2C,     InstProps.Ra  | InstProps.Pd  | InstProps.Pdn);
+            Add("0101110100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2R,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0111110x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2I,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("0111110x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hset2,       InstEmit.Hset2C,      InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
+            Add("0101110100100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2R,     InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("0111111x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2I,     InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("0111111x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Hsetp2,      InstEmit.Hsetp2C,     InstProps.Ra  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("0101110010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f,         InstEmit.I2fR,        InstProps.Rd  | InstProps.Rb);
             Add("0011100x10111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f,         InstEmit.I2fI,        InstProps.Rd  | InstProps.Ib);
             Add("0100110010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.I2f,         InstEmit.I2fC,        InstProps.Rd);
@@ -168,9 +168,9 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0011010x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp,      InstEmit.ImadspI,     InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
             Add("010010101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp,      InstEmit.ImadspC,     InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
             Add("010100101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imadsp,      InstEmit.ImadspRc,    InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
-            Add("0101110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011100x00100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("0100110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxC,      InstProps.Rd  | InstProps.Ra);
+            Add("0101110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011100x00100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxI,      InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("0100110000100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imnmx,       InstEmit.ImnmxC,      InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
             Add("0101110000111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul,        InstEmit.ImulR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x00111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul,        InstEmit.ImulI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110000111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Imul,        InstEmit.ImulC,       InstProps.Rd  | InstProps.Ra);
@@ -181,12 +181,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0011100x00011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd,      InstEmit.IscaddI,     InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110000011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd,      InstEmit.IscaddC,     InstProps.Rd  | InstProps.Ra);
             Add("000101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iscadd32i,   InstEmit.Iscadd32i,   InstProps.Rd  | InstProps.Ra);
-            Add("010110110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011011x0101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("010010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetC,       InstProps.Rd  | InstProps.Ra);
-            Add("010110110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn);
-            Add("0011011x0110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn);
-            Add("010010110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn);
+            Add("010110110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011011x0101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("010010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Iset,        InstEmit.IsetC,       InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
+            Add("010110110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpR,      InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("0011011x0110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpI,      InstProps.Ra  | InstProps.Ib  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
+            Add("010010110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Isetp,       InstEmit.IsetpC,      InstProps.Ra  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("111000100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jcal,        InstEmit.Jcal,        InstProps.Bra);
             Add("111000100001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jmp,         InstEmit.Jmp,         InstProps.Ra  | InstProps.Bra);
             Add("111000100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Jmx,         InstEmit.Jmx,         InstProps.Ra  | InstProps.Bra);
@@ -196,17 +196,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("1110111011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldg,         InstEmit.Ldg,         InstProps.Rd  | InstProps.Ra);
             Add("1110111101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldl,         InstEmit.Ldl,         InstProps.Rd  | InstProps.Ra);
             Add("1110111101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lds,         InstEmit.Lds,         InstProps.Rd  | InstProps.Ra);
-            Add("0101101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd);
-            Add("0011011x11010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Pd);
-            Add("0100101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaC,        InstProps.Rd  | InstProps.Ra  | InstProps.Pd);
-            Add("0101101111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi,       InstEmit.LeaHiR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.Pd);
-            Add("000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi,       InstEmit.LeaHiC,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.Pd);
+            Add("0101101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.LPd);
+            Add("0011011x11010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.LPd);
+            Add("0100101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lea,         InstEmit.LeaC,        InstProps.Rd  | InstProps.Ra  | InstProps.LPd);
+            Add("0101101111011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi,       InstEmit.LeaHiR,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.LPd);
+            Add("000110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.LeaHi,       InstEmit.LeaHiC,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.LPd);
             Add("0101000011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lepc,        InstEmit.Lepc);
             Add("111000110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Longjmp,     InstEmit.Longjmp,     InstProps.Bra);
-            Add("0101110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd);
-            Add("0011100x01000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Pd);
-            Add("0100110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopC,        InstProps.Rd  | InstProps.Ra  | InstProps.Pd);
-            Add("0101101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3,        InstEmit.Lop3R,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.Pd);
+            Add("0101110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.LPd);
+            Add("0011100x01000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.LPd);
+            Add("0100110001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop,         InstEmit.LopC,        InstProps.Rd  | InstProps.Ra  | InstProps.LPd);
+            Add("0101101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3,        InstEmit.Lop3R,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.LPd);
             Add("001111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3,        InstEmit.Lop3I,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
             Add("0000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop3,        InstEmit.Lop3C,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
             Add("000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Lop32i,      InstEmit.Lop32i,      InstProps.Rd  | InstProps.Ra);
@@ -226,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("111000101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pbk,         InstEmit.Pbk,         InstProps.NoPred);
             Add("111000101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pcnt,        InstEmit.Pcnt,        InstProps.NoPred);
             Add("111000100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pexit,       InstEmit.Pexit);
-            Add("1110111111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pixld,       InstEmit.Pixld,       InstProps.Rd  | InstProps.Ra);
+            Add("1110111111101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pixld,       InstEmit.Pixld,       InstProps.Rd  | InstProps.Ra  | InstProps.VPd);
             Add("111000101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Plongjmp,    InstEmit.Plongjmp,    InstProps.Bra | InstProps.NoPred);
             Add("0101110000001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Popc,        InstEmit.PopcR,       InstProps.Rd  | InstProps.Rb);
             Add("0011100x00001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Popc,        InstEmit.PopcI,       InstProps.Rd  | InstProps.Ib);
@@ -236,14 +236,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("0011011x1100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt,        InstEmit.PrmtI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
             Add("010010111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt,        InstEmit.PrmtC,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
             Add("010100111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Prmt,        InstEmit.PrmtRc,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
-            Add("0101000010001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pset,        InstEmit.Pset,        InstProps.Rd);
-            Add("0101000010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Psetp,       InstEmit.Psetp,       InstProps.Pd  | InstProps.Pdn);
+            Add("0101000010001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pset,        InstEmit.Pset,        InstProps.Rd  | InstProps.Ps);
+            Add("0101000010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Psetp,       InstEmit.Psetp,       InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("1111000011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2b,         InstEmit.R2b,         InstProps.Rb);
             Add("0101110011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p,         InstEmit.R2pR,        InstProps.Ra  | InstProps.Rb);
             Add("0011100x11110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p,         InstEmit.R2pI,        InstProps.Ra  | InstProps.Ib);
             Add("0100110011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.R2p,         InstEmit.R2pC,        InstProps.Ra);
             Add("111000111000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ram,         InstEmit.Ram,         InstProps.NoPred);
-            Add("1110101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Red,         InstEmit.Red,         InstProps.Ra);
+            Add("1110101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Red,         InstEmit.Red,         InstProps.Ra  | InstProps.Rb2);
             Add("111000110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ret,         InstEmit.Ret,         InstProps.Bra);
             Add("0101110010010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rro,         InstEmit.RroR,        InstProps.Rd  | InstProps.Rb);
             Add("0011100x10010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rro,         InstEmit.RroI,        InstProps.Rd  | InstProps.Ib);
@@ -251,16 +251,16 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("111000110110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Rtt,         InstEmit.Rtt,         InstProps.NoPred);
             Add("1111000011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.S2r,         InstEmit.S2r,         InstProps.Rd);
             Add("111000110111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sam,         InstEmit.Sam,         InstProps.NoPred);
-            Add("0101110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
-            Add("0011100x10100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
-            Add("0100110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelC,        InstProps.Rd  | InstProps.Ra);
+            Add("0101110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Ps);
+            Add("0011100x10100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Ps);
+            Add("0100110010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sel,         InstEmit.SelC,        InstProps.Rd  | InstProps.Ra  | InstProps.Ps);
             Add("111000101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Setcrsptr,   InstEmit.Setcrsptr,   InstProps.Ra  | InstProps.NoPred);
             Add("111000101111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Setlmembase, InstEmit.Setlmembase, InstProps.Ra  | InstProps.NoPred);
             Add("0101101111111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf,         InstEmit.ShfLR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("0101110011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf,         InstEmit.ShfRR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("0011011x11111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf,         InstEmit.ShfLI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
             Add("0011100x11111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shf,         InstEmit.ShfRI,       InstProps.Rd  | InstProps.Ra  | InstProps.Ib  | InstProps.Rc);
-            Add("1110111100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shfl,        InstEmit.Shfl,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.Pd);
+            Add("1110111100010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shfl,        InstEmit.Shfl,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.LPd);
             Add("0101110001001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl,         InstEmit.ShlR,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("0011100x01001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl,         InstEmit.ShlI,        InstProps.Rd  | InstProps.Ra  | InstProps.Ib);
             Add("0100110001001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Shl,         InstEmit.ShlC,        InstProps.Rd  | InstProps.Ra);
@@ -276,12 +276,12 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("1110101001110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB,     InstEmit.SuatomB,     InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("11101010x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suatom,      InstEmit.Suatom,      InstProps.Rd  | InstProps.Ra  | InstProps.Rb);
             Add("1110101110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomB2,    InstEmit.SuatomB2,    InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
-            Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB,  InstEmit.SuatomCasB,  InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.Pd2);
-            Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas,   InstEmit.SuatomCas,   InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd2);
-            Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB,      InstEmit.SuldDB,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.Pd2 | InstProps.TexB);
-            Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD,       InstEmit.SuldD,       InstProps.Rd  | InstProps.Ra  | InstProps.Pd2 | InstProps.Tex);
-            Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB,       InstEmit.SuldB,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.Pd2 | InstProps.TexB);
-            Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld,        InstEmit.Suld,        InstProps.Rd  | InstProps.Ra  | InstProps.Pd2 | InstProps.Tex);
+            Add("1110101011010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCasB,  InstEmit.SuatomCasB,  InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc  | InstProps.SPd);
+            Add("1110101x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuatomCas,   InstEmit.SuatomCas,   InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.SPd);
+            Add("111010110001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldDB,      InstEmit.SuldDB,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.SPd | InstProps.TexB);
+            Add("1110101100011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldD,       InstEmit.SuldD,       InstProps.Rd  | InstProps.Ra  | InstProps.SPd | InstProps.Tex);
+            Add("11101011000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuldB,       InstEmit.SuldB,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.SPd | InstProps.TexB);
+            Add("11101011000x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Suld,        InstEmit.Suld,        InstProps.Rd  | InstProps.Ra  | InstProps.SPd | InstProps.Tex);
             Add("111010110101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SuredB,      InstEmit.SuredB,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc);
             Add("1110101101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sured,       InstEmit.Sured,       InstProps.Rd  | InstProps.Ra);
             Add("111010110011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustDB,      InstEmit.SustDB,      InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.TexB);
@@ -289,23 +289,23 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("11101011001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.SustB,       InstEmit.SustB,       InstProps.Rd  | InstProps.Ra  | InstProps.Rc  | InstProps.TexB);
             Add("11101011001x1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sust,        InstEmit.Sust,        InstProps.Rd  | InstProps.Ra  | InstProps.Tex);
             Add("1111000011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Sync,        InstEmit.Sync,        InstProps.Bra);
-            Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex,         InstEmit.Tex,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Tex);
-            Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB,        InstEmit.TexB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.TexB);
+            Add("11000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tex,         InstEmit.Tex,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.Tex);
+            Add("1101111010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexB,        InstEmit.TexB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.TexB);
             Add("1101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Texs,        InstEmit.Texs,        InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
             Add("1101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TexsF16,     InstEmit.TexsF16,     InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
-            Add("11011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld,         InstEmit.Tld,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Tex);
-            Add("11011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldB,        InstEmit.TldB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.TexB);
+            Add("11011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld,         InstEmit.Tld,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.Tex);
+            Add("11011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldB,        InstEmit.TldB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.TexB);
             Add("1101101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tlds,        InstEmit.Tlds,        InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
             Add("1101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TldsF16,     InstEmit.TldsF16,     InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
-            Add("110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4,        InstEmit.Tld4,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Tex);
-            Add("1101111011xxxxxxxxxxxxx0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4B,       InstEmit.Tld4B,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.TexB);
+            Add("110010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4,        InstEmit.Tld4,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.Tex);
+            Add("1101111011xxxxxxxxxxxxx0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4B,       InstEmit.Tld4B,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.TexB);
             Add("1101111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4s,       InstEmit.Tld4s,       InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
             Add("1101111110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tld4sF16,    InstEmit.Tld4sF16,    InstProps.Rd  | InstProps.Rd2 | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
             Add("1101111101011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tmml,        InstEmit.Tmml,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Tex);
             Add("1101111101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TmmlB,       InstEmit.TmmlB,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TexB);
             Add("1101111101000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txa,         InstEmit.Txa,         InstProps.Rd  | InstProps.Ra  | InstProps.Tex);
-            Add("110111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txd,         InstEmit.Txd,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Tex);
-            Add("1101111001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxdB,        InstEmit.TxdB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.TexB);
+            Add("110111100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txd,         InstEmit.Txd,         InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.Tex);
+            Add("1101111001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxdB,        InstEmit.TxdB,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.TPd | InstProps.TexB);
             Add("1101111101001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Txq,         InstEmit.Txq,         InstProps.Rd  | InstProps.Ra  | InstProps.Tex);
             Add("1101111101010xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.TxqB,        InstEmit.TxqB,        InstProps.Rd  | InstProps.Ra  | InstProps.TexB);
             Add("01010100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vabsdiff,    InstEmit.Vabsdiff,    InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
@@ -313,10 +313,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
             Add("001000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vadd,        InstEmit.Vadd,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("01011111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vmad,        InstEmit.Vmad,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("0011101xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vmnmx,       InstEmit.Vmnmx,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
-            Add("0101000011011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vote,        InstEmit.Vote,        InstProps.Rd);
+            Add("0101000011011xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vote,        InstEmit.Vote,        InstProps.Rd  | InstProps.VPd | InstProps.Ps);
             Add("0101000011100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Votevtg,     InstEmit.Votevtg);
             Add("0100000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vset,        InstEmit.Vset,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
-            Add("0101000011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vsetp,       InstEmit.Vsetp,       InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn);
+            Add("0101000011110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vsetp,       InstEmit.Vsetp,       InstProps.Ra  | InstProps.Rb  | InstProps.Pd  | InstProps.Pdn | InstProps.Ps);
             Add("01010111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vshl,        InstEmit.Vshl,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("01010110xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Vshr,        InstEmit.Vshr,        InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
             Add("0101101100xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Xmad,        InstEmit.XmadR,       InstProps.Rd  | InstProps.Ra  | InstProps.Rb  | InstProps.Rc);
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 3fdce8ea6d..a6ccdedd5d 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -61,6 +61,16 @@ namespace Ryujinx.Graphics.Shader
             return 16;
         }
 
+        bool QueryHostSupportsFragmentShaderInterlock()
+        {
+            return true;
+        }
+
+        bool QueryHostSupportsFragmentShaderOrderingIntel()
+        {
+            return false;
+        }
+
         bool QueryHostSupportsImageLoadFormatted()
         {
             return true;
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs
index 33c1065ae6..c5a1e13526 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmit.cs
@@ -56,14 +56,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
         public static void Cont(EmitterContext context)
         {
-            InstContUnsup op = context.GetOp<InstContUnsup>();
+            InstCont op = context.GetOp<InstCont>();
 
             context.Config.GpuAccessor.Log("Shader instruction ContUnsup is not implemented.");
         }
 
         public static void Cset(EmitterContext context)
         {
-            InstCsetUnsup op = context.GetOp<InstCsetUnsup>();
+            InstCset op = context.GetOp<InstCset>();
 
             context.Config.GpuAccessor.Log("Shader instruction CsetUnsup is not implemented.");
         }
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs
index fce951ba68..da34c1be53 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitFlowControl.cs
@@ -67,7 +67,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
         {
             InstCal op = context.GetOp<InstCal>();
 
-            context.Call(context.GetFunctionId(context.CurrOp.GetAbsoluteAddress()), false);
+            DecodedFunction function = context.Program.GetFunctionByAddress(context.CurrOp.GetAbsoluteAddress());
+
+            if (function.IsCompilerGenerated)
+            {
+                switch (function.Type)
+                {
+                    case FunctionType.BuiltInFSIBegin:
+                        context.FSIBegin();
+                        break;
+                    case FunctionType.BuiltInFSIEnd:
+                        context.FSIEnd();
+                        break;
+                }
+            }
+            else
+            {
+                context.Call(function.Id, false);
+            }
         }
 
         public static void Exit(EmitterContext context)
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
index f78f9db895..5959ac964e 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitSurface.cs
@@ -109,28 +109,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
         {
             InstSuldDB op = context.GetOp<InstSuldDB>();
 
-            EmitSuld(context, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
+            EmitSuld(context, op.CacheOp, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
         }
 
         public static void SuldD(EmitterContext context)
         {
             InstSuldD op = context.GetOp<InstSuldD>();
 
-            EmitSuld(context, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
+            EmitSuld(context, op.CacheOp, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
         }
 
         public static void SuldB(EmitterContext context)
         {
             InstSuldB op = context.GetOp<InstSuldB>();
 
-            EmitSuld(context, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
+            EmitSuld(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: true);
         }
 
         public static void Suld(EmitterContext context)
         {
             InstSuld op = context.GetOp<InstSuld>();
 
-            EmitSuld(context, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
+            EmitSuld(context, op.CacheOp, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
         }
 
         public static void SuredB(EmitterContext context)
@@ -151,28 +151,28 @@ namespace Ryujinx.Graphics.Shader.Instructions
         {
             InstSustDB op = context.GetOp<InstSustDB>();
 
-            EmitSust(context, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
+            EmitSust(context, op.CacheOp, op.Dim, op.Size, 0, 0, op.SrcA, op.Dest, op.SrcC, useComponents: false, op.Ba, isBindless: true);
         }
 
         public static void SustD(EmitterContext context)
         {
             InstSustD op = context.GetOp<InstSustD>();
 
-            EmitSust(context, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
+            EmitSust(context, op.CacheOp, op.Dim, op.Size, op.TidB, 0, op.SrcA, op.Dest, 0, useComponents: false, op.Ba, isBindless: false);
         }
 
         public static void SustB(EmitterContext context)
         {
             InstSustB op = context.GetOp<InstSustB>();
 
-            EmitSust(context, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
+            EmitSust(context, op.CacheOp, op.Dim, 0, 0, op.Rgba, op.SrcA, op.Dest, op.SrcC, useComponents: true, false, isBindless: true);
         }
 
         public static void Sust(EmitterContext context)
         {
             InstSust op = context.GetOp<InstSust>();
 
-            EmitSust(context, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
+            EmitSust(context, op.CacheOp, op.Dim, 0, op.TidB, op.Rgba, op.SrcA, op.Dest, 0, useComponents: true, false, isBindless: false);
         }
 
         private static void EmitSuatom(
@@ -299,6 +299,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
         private static void EmitSuld(
             EmitterContext context,
+            CacheOpLd cacheOp,
             SuDim dimensions,
             SuSize size,
             int imm,
@@ -363,6 +364,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
             TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
 
+            if (cacheOp == CacheOpLd.Cg)
+            {
+                flags |= TextureFlags.Coherent;
+            }
+
             if (useComponents)
             {
                 for (int compMask = (int)componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
@@ -546,6 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
         private static void EmitSust(
             EmitterContext context,
+            CacheOpSt cacheOp,
             SuDim dimensions,
             SuSize size,
             int imm,
@@ -654,6 +661,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
             TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
 
+            if (cacheOp == CacheOpSt.Cg)
+            {
+                flags |= TextureFlags.Coherent;
+            }
+
             TextureOperation operation = context.CreateTextureOperation(
                 Instruction.ImageStore,
                 type,
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
index e04e61a7e8..791c8f11cd 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs
@@ -62,6 +62,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
         EmitVertex,
         EndPrimitive,
         ExponentB2,
+        FSIBegin,
+        FSIEnd,
         FindFirstSetS32,
         FindFirstSetU32,
         Floor,
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs
index 0cc938a331..6c20e856f9 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs
@@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
         LodLevel    = 1 << 5,
         Offset      = 1 << 6,
         Offsets     = 1 << 7,
+        Coherent    = 1 << 8,
 
         AtomicMask  = 15 << 16,
 
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs
index e56008f093..34428815ec 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/OperandInfo.cs
@@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
         {
             return type switch
             {
+                OperandType.Argument => VariableType.S32,
                 OperandType.Attribute => VariableType.F32,
                 OperandType.AttributePerPatch => VariableType.F32,
                 OperandType.Constant => VariableType.S32,
diff --git a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
index 87be0d0114..2419a1de49 100644
--- a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
+++ b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
@@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Shader
         // Integer sampled textures must be noted for resolution scaling.
         ResScaleUnsupported = 1 << 0,
         NeedsScaleValue = 1 << 1,
-        ImageStore = 1 << 2
+        ImageStore = 1 << 2,
+        ImageCoherent = 1 << 3
     }
 }
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 6f2a6c3b3f..2f839b7adb 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -10,24 +10,24 @@ namespace Ryujinx.Graphics.Shader.Translation
 {
     class EmitterContext
     {
-        public Block  CurrBlock { get; set; }
-        public InstOp CurrOp    { get; set; }
-
+        public DecodedProgram Program { get; }
         public ShaderConfig Config { get; }
 
         public bool IsNonMain { get; }
 
+        public Block CurrBlock { get; set; }
+        public InstOp CurrOp { get; set; }
+
         public int OperationsCount => _operations.Count;
 
-        private readonly IReadOnlyDictionary<ulong, int> _funcs;
         private readonly List<Operation> _operations;
         private readonly Dictionary<ulong, Operand> _labels;
 
-        public EmitterContext(ShaderConfig config, bool isNonMain, IReadOnlyDictionary<ulong, int> funcs)
+        public EmitterContext(DecodedProgram program, ShaderConfig config, bool isNonMain)
         {
+            Program = program;
             Config = config;
             IsNonMain = isNonMain;
-            _funcs = funcs;
             _operations = new List<Operation>();
             _labels = new Dictionary<ulong, Operand>();
         }
@@ -154,11 +154,6 @@ namespace Ryujinx.Graphics.Shader.Translation
             return label;
         }
 
-        public int GetFunctionId(ulong address)
-        {
-            return _funcs[address];
-        }
-
         public void PrepareForReturn()
         {
             if (!IsNonMain && Config.Stage == ShaderStage.Fragment)
@@ -195,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation
                             Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
 
                             Operand lblIsBgra = Label();
-                            Operand lblEnd    = Label();
+                            Operand lblEnd = Label();
 
                             this.BranchIfTrue(lblIsBgra, isBgra);
 
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
index a8fef95b3b..5e607b44b0 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContextInsts.cs
@@ -361,6 +361,16 @@ namespace Ryujinx.Graphics.Shader.Translation
             return context.Add(Instruction.SwizzleAdd, Local(), a, b, Const(mask));
         }
 
+        public static void FSIBegin(this EmitterContext context)
+        {
+            context.Add(Instruction.FSIBegin);
+        }
+
+        public static void FSIEnd(this EmitterContext context)
+        {
+            context.Add(Instruction.FSIEnd);
+        }
+
         public static Operand GroupMemoryBarrier(this EmitterContext context)
         {
             return context.Add(Instruction.GroupMemoryBarrier);
diff --git a/Ryujinx.Graphics.Shader/Translation/FunctionMatch.cs b/Ryujinx.Graphics.Shader/Translation/FunctionMatch.cs
new file mode 100644
index 0000000000..1c5d8c545f
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/FunctionMatch.cs
@@ -0,0 +1,866 @@
+using Ryujinx.Graphics.Shader.Decoders;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Graphics.Shader.Translation
+{
+    static class FunctionMatch
+    {
+        private static IPatternTreeNode[] _fsiGetAddressTree = PatternTrees.GetFsiGetAddress();
+        private static IPatternTreeNode[] _fsiGetAddressV2Tree = PatternTrees.GetFsiGetAddressV2();
+        private static IPatternTreeNode[] _fsiIsLastWarpThreadPatternTree = PatternTrees.GetFsiIsLastWarpThread();
+        private static IPatternTreeNode[] _fsiBeginPatternTree = PatternTrees.GetFsiBeginPattern();
+        private static IPatternTreeNode[] _fsiEndPatternTree = PatternTrees.GetFsiEndPattern();
+
+        public static void RunPass(DecodedProgram program)
+        {
+            byte[] externalRegs = new byte[4];
+            bool hasGetAddress = false;
+
+            foreach (DecodedFunction function in program)
+            {
+                if (function == program.MainFunction)
+                {
+                    continue;
+                }
+
+                int externalReg4 = 0;
+
+                TreeNode[] functionTree = BuildTree(function.Blocks);
+
+                if (Matches(_fsiGetAddressTree, functionTree))
+                {
+                    externalRegs[1] = functionTree[0].GetRd();
+                    externalRegs[2] = functionTree[2].GetRd();
+                    externalRegs[3] = functionTree[1].GetRd();
+                    externalReg4 = functionTree[3].GetRd();
+                }
+                else if (Matches(_fsiGetAddressV2Tree, functionTree))
+                {
+                    externalRegs[1] = functionTree[2].GetRd();
+                    externalRegs[2] = functionTree[1].GetRd();
+                    externalRegs[3] = functionTree[0].GetRd();
+                    externalReg4 = functionTree[3].GetRd();
+                }
+
+                // Ensure the register allocation is valid.
+                // If so, then we have a match.
+                if (externalRegs[1] != externalRegs[2] &&
+                    externalRegs[2] != externalRegs[3] &&
+                    externalRegs[1] != externalRegs[3] &&
+                    externalRegs[1] + 1 != externalRegs[2] &&
+                    externalRegs[1] + 1 != externalRegs[3] &&
+                    externalRegs[1] + 1 == externalReg4 &&
+                    externalRegs[2] != RegisterConsts.RegisterZeroIndex &&
+                    externalRegs[3] != RegisterConsts.RegisterZeroIndex &&
+                    externalReg4 != RegisterConsts.RegisterZeroIndex)
+                {
+                    hasGetAddress = true;
+                    function.Type = FunctionType.Unused;
+                    break;
+                }
+            }
+
+            foreach (DecodedFunction function in program)
+            {
+                if (function.IsCompilerGenerated || function == program.MainFunction)
+                {
+                    continue;
+                }
+
+                if (hasGetAddress)
+                {
+                    TreeNode[] functionTree = BuildTree(function.Blocks);
+
+                    if (MatchesFsi(_fsiBeginPatternTree, program, function, functionTree, externalRegs))
+                    {
+                        function.Type = FunctionType.BuiltInFSIBegin;
+                        continue;
+                    }
+                    else if (MatchesFsi(_fsiEndPatternTree, program, function, functionTree, externalRegs))
+                    {
+                        function.Type = FunctionType.BuiltInFSIEnd;
+                        continue;
+                    }
+                }
+            }
+        }
+
+        private struct TreeNodeUse
+        {
+            public TreeNode Node { get; }
+            public int Index { get; }
+            public bool Inverted { get; }
+
+            private TreeNodeUse(int index, bool inverted, TreeNode node)
+            {
+                Index = index;
+                Inverted = inverted;
+                Node = node;
+            }
+
+            public TreeNodeUse(int index, TreeNode node) : this(index, false, node)
+            {
+            }
+
+            public TreeNodeUse Flip()
+            {
+                return new TreeNodeUse(Index, !Inverted, Node);
+            }
+        }
+
+        private enum TreeNodeType : byte
+        {
+            Op,
+            Label
+        }
+
+        private class TreeNode
+        {
+            public readonly InstOp Op;
+            public readonly List<TreeNodeUse> Uses;
+            public TreeNodeType Type { get; }
+            public byte Order { get; }
+
+            public TreeNode(byte order)
+            {
+                Type = TreeNodeType.Label;
+                Order = order;
+            }
+
+            public TreeNode(InstOp op, byte order)
+            {
+                Op = op;
+                Uses = new List<TreeNodeUse>();
+                Type = TreeNodeType.Op;
+                Order = order;
+            }
+
+            public byte GetPd()
+            {
+                return (byte)((Op.RawOpCode >> 3) & 7);
+            }
+
+            public byte GetRd()
+            {
+                return (byte)Op.RawOpCode;
+            }
+        }
+
+        private static TreeNode[] BuildTree(Block[] blocks)
+        {
+            List<TreeNode> nodes = new List<TreeNode>();
+
+            Dictionary<ulong, TreeNode> labels = new Dictionary<ulong, TreeNode>();
+
+            TreeNodeUse[] predDefs = new TreeNodeUse[RegisterConsts.PredsCount];
+            TreeNodeUse[] gprDefs = new TreeNodeUse[RegisterConsts.GprsCount];
+
+            void DefPred(byte predIndex, int index, TreeNode node)
+            {
+                if (predIndex != RegisterConsts.PredicateTrueIndex)
+                {
+                    predDefs[predIndex] = new TreeNodeUse(index, node);
+                }
+            }
+
+            void DefGpr(byte regIndex, int index, TreeNode node)
+            {
+                if (regIndex != RegisterConsts.RegisterZeroIndex)
+                {
+                    gprDefs[regIndex] = new TreeNodeUse(index, node);
+                }
+            }
+
+            TreeNodeUse UsePred(byte predIndex, bool predInv)
+            {
+                if (predIndex != RegisterConsts.PredicateTrueIndex)
+                {
+                    TreeNodeUse use = predDefs[predIndex];
+
+                    if (use.Node != null)
+                    {
+                        nodes.Remove(use.Node);
+                    }
+                    else
+                    {
+                        use = new TreeNodeUse(-(predIndex + 2), null);
+                    }
+
+                    return predInv ? use.Flip() : use;
+                }
+
+                return new TreeNodeUse(-1, null);
+            }
+
+            TreeNodeUse UseGpr(byte regIndex)
+            {
+                if (regIndex != RegisterConsts.RegisterZeroIndex)
+                {
+                    TreeNodeUse use = gprDefs[regIndex];
+
+                    if (use.Node != null)
+                    {
+                        nodes.Remove(use.Node);
+                    }
+                    else
+                    {
+                        use = new TreeNodeUse(-(regIndex + 2), null);
+                    }
+
+                    return use;
+                }
+
+                return new TreeNodeUse(-1, null);
+            }
+
+            byte order = 0;
+
+            for (int index = 0; index < blocks.Length; index++)
+            {
+                Block block = blocks[index];
+
+                if (block.Predecessors.Count > 1)
+                {
+                    TreeNode label = new TreeNode(order++);
+                    nodes.Add(label);
+                    labels.Add(block.Address, label);
+                }
+
+                for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++)
+                {
+                    InstOp op = block.OpCodes[opIndex];
+
+                    TreeNode node = new TreeNode(op, IsOrderDependant(op.Name) ? order : (byte)0);
+
+                    // Add uses.
+
+                    if (!op.Props.HasFlag(InstProps.NoPred))
+                    {
+                        byte predIndex = (byte)((op.RawOpCode >> 16) & 7);
+                        bool predInv = (op.RawOpCode & 0x80000) != 0;
+                        node.Uses.Add(UsePred(predIndex, predInv));
+                    }
+
+                    if (op.Props.HasFlag(InstProps.Ps))
+                    {
+                        byte predIndex = (byte)((op.RawOpCode >> 39) & 7);
+                        bool predInv = (op.RawOpCode & 0x40000000000) != 0;
+                        node.Uses.Add(UsePred(predIndex, predInv));
+                    }
+
+                    if (op.Props.HasFlag(InstProps.Ra))
+                    {
+                        byte ra = (byte)(op.RawOpCode >> 8);
+                        node.Uses.Add(UseGpr(ra));
+                    }
+
+                    if ((op.Props & (InstProps.Rb | InstProps.Rb2)) != 0)
+                    {
+                        byte rb = op.Props.HasFlag(InstProps.Rb2) ? (byte)op.RawOpCode : (byte)(op.RawOpCode >> 20);
+                        node.Uses.Add(UseGpr(rb));
+                    }
+
+                    if (op.Props.HasFlag(InstProps.Rc))
+                    {
+                        byte rc = (byte)(op.RawOpCode >> 39);
+                        node.Uses.Add(UseGpr(rc));
+                    }
+
+                    if (op.Name == InstName.Bra && labels.TryGetValue(op.GetAbsoluteAddress(), out TreeNode label))
+                    {
+                        node.Uses.Add(new TreeNodeUse(0, label));
+                    }
+
+                    // Make definitions.
+
+                    int defIndex = 0;
+
+                    InstProps pdType = op.Props & InstProps.PdMask;
+
+                    if (pdType != 0)
+                    {
+                        int bit = pdType switch
+                        {
+                            InstProps.Pd => 3,
+                            InstProps.LPd => 48,
+                            InstProps.SPd => 30,
+                            InstProps.TPd => 51,
+                            InstProps.VPd => 45,
+                            _ => throw new InvalidOperationException($"Table has unknown predicate destination {pdType}.")
+                        };
+
+                        byte predIndex = (byte)((op.RawOpCode >> bit) & 7);
+                        DefPred(predIndex, defIndex++, node);
+                    }
+
+                    if (op.Props.HasFlag(InstProps.Rd))
+                    {
+                        byte rd = (byte)op.RawOpCode;
+                        DefGpr(rd, defIndex++, node);
+                    }
+
+                    nodes.Add(node);
+                }
+            }
+
+            return nodes.ToArray();
+        }
+
+        private static bool IsOrderDependant(InstName name)
+        {
+            switch (name)
+            {
+                case InstName.Atom:
+                case InstName.AtomCas:
+                case InstName.Atoms:
+                case InstName.AtomsCas:
+                case InstName.Ld:
+                case InstName.Ldg:
+                case InstName.Ldl:
+                case InstName.Lds:
+                case InstName.Suatom:
+                case InstName.SuatomB:
+                case InstName.SuatomB2:
+                case InstName.SuatomCas:
+                case InstName.SuatomCasB:
+                case InstName.Suld:
+                case InstName.SuldB:
+                case InstName.SuldD:
+                case InstName.SuldDB:
+                    return true;
+            }
+
+            return false;
+        }
+
+        private interface IPatternTreeNode
+        {
+            List<PatternTreeNodeUse> Uses { get; }
+            InstName Name { get; }
+            TreeNodeType Type { get; }
+            byte Order { get; }
+            bool IsImm { get; }
+            bool Matches(in InstOp opInfo);
+        }
+
+        private struct PatternTreeNodeUse
+        {
+            public IPatternTreeNode Node { get; }
+            public int Index { get; }
+            public bool Inverted { get; }
+            public PatternTreeNodeUse Inv => new PatternTreeNodeUse(Index, !Inverted, Node);
+
+            private PatternTreeNodeUse(int index, bool inverted, IPatternTreeNode node)
+            {
+                Index = index;
+                Inverted = inverted;
+                Node = node;
+            }
+
+            public PatternTreeNodeUse(int index, IPatternTreeNode node) : this(index, false, node)
+            {
+            }
+        }
+
+        private class PatternTreeNode<T> : IPatternTreeNode
+        {
+            public List<PatternTreeNodeUse> Uses { get; }
+            private readonly Func<T, bool> _match;
+
+            public InstName Name { get; }
+            public TreeNodeType Type { get; }
+            public byte Order { get; }
+            public bool IsImm { get; }
+            public PatternTreeNodeUse Out => new PatternTreeNodeUse(0, this);
+
+            public PatternTreeNode(InstName name, Func<T, bool> match, TreeNodeType type = TreeNodeType.Op, byte order = 0, bool isImm = false)
+            {
+                Name = name;
+                _match = match;
+                Type = type;
+                Order = order;
+                IsImm = isImm;
+                Uses = new List<PatternTreeNodeUse>();
+            }
+
+            public PatternTreeNode<T> Use(PatternTreeNodeUse use)
+            {
+                Uses.Add(use);
+                return this;
+            }
+
+            public PatternTreeNodeUse OutAt(int index)
+            {
+                return new PatternTreeNodeUse(index, this);
+            }
+
+            public bool Matches(in InstOp opInfo)
+            {
+                if (opInfo.Name != Name)
+                {
+                    return false;
+                }
+
+                ulong rawOp = opInfo.RawOpCode;
+                T op = Unsafe.As<ulong, T>(ref rawOp);
+
+                if (!_match(op))
+                {
+                    return false;
+                }
+
+                return true;
+            }
+        }
+
+        private static bool MatchesFsi(
+            IPatternTreeNode[] pattern,
+            DecodedProgram program,
+            DecodedFunction function,
+            TreeNode[] functionTree,
+            byte[] externalRegs)
+        {
+            if (function.Blocks.Length == 0)
+            {
+                return false;
+            }
+
+            InstOp callOp = function.Blocks[0].GetLastOp();
+
+            if (callOp.Name != InstName.Cal)
+            {
+                return false;
+            }
+
+            DecodedFunction callTarget = program.GetFunctionByAddress(callOp.GetAbsoluteAddress());
+            TreeNode[] callTargetTree = null;
+
+            if (callTarget == null || !Matches(_fsiIsLastWarpThreadPatternTree, callTargetTree = BuildTree(callTarget.Blocks)))
+            {
+                return false;
+            }
+
+            externalRegs[0] = callTargetTree[0].GetPd();
+
+            if (Matches(pattern, functionTree, externalRegs))
+            {
+                callTarget.RemoveCaller(function);
+                return true;
+            }
+
+            return false;
+        }
+
+        private static bool Matches(IPatternTreeNode[] pTree, TreeNode[] cTree, byte[] externalRegs = null)
+        {
+            if (pTree.Length != cTree.Length)
+            {
+                return false;
+            }
+
+            for (int index = 0; index < pTree.Length; index++)
+            {
+                if (!Matches(pTree[index], cTree[index], externalRegs))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool Matches(IPatternTreeNode pTreeNode, TreeNode cTreeNode, byte[] externalRegs)
+        {
+            if (!pTreeNode.Matches(in cTreeNode.Op) ||
+                pTreeNode.Type != cTreeNode.Type ||
+                pTreeNode.Order != cTreeNode.Order ||
+                pTreeNode.IsImm != cTreeNode.Op.Props.HasFlag(InstProps.Ib))
+            {
+                return false;
+            }
+
+            if (pTreeNode.Type == TreeNodeType.Op)
+            {
+                if (pTreeNode.Uses.Count != cTreeNode.Uses.Count)
+                {
+                    return false;
+                }
+
+                for (int index = 0; index < pTreeNode.Uses.Count; index++)
+                {
+                    var pUse = pTreeNode.Uses[index];
+                    var cUse = cTreeNode.Uses[index];
+
+                    if (pUse.Index <= -2)
+                    {
+                        if (externalRegs[-pUse.Index - 2] != (-cUse.Index - 2))
+                        {
+                            return false;
+                        }
+                    }
+                    else if (pUse.Index != cUse.Index)
+                    {
+                        return false;
+                    }
+
+                    if (pUse.Inverted != cUse.Inverted || (pUse.Node == null) != (cUse.Node == null))
+                    {
+                        return false;
+                    }
+
+                    if (pUse.Node != null && !Matches(pUse.Node, cUse.Node, externalRegs))
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        private static class PatternTrees
+        {
+            public static IPatternTreeNode[] GetFsiGetAddress()
+            {
+                var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
+                var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
+
+                return new IPatternTreeNode[]
+                {
+                    Iscadd(cc: true, 2, 0, 404)
+                        .Use(PT)
+                        .Use(Iscadd(cc: false, 8)
+                            .Use(PT)
+                            .Use(Lop32i(LogicOp.And, 0xff)
+                                .Use(PT)
+                                .Use(affinityValue).Out)
+                            .Use(Lop32i(LogicOp.And, 0xff)
+                                .Use(PT)
+                                .Use(orderingTicketValue).Out).Out),
+                    ShrU32W(16)
+                        .Use(PT)
+                        .Use(orderingTicketValue),
+                    Iadd32i(0x200)
+                        .Use(PT)
+                        .Use(Lop32i(LogicOp.And, 0xfe00)
+                            .Use(PT)
+                            .Use(orderingTicketValue).Out),
+                    Iadd(x: true, 0, 405).Use(PT).Use(RZ),
+                    Ret().Use(PT)
+                };
+            }
+
+            public static IPatternTreeNode[] GetFsiGetAddressV2()
+            {
+                var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
+                var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
+
+                return new IPatternTreeNode[]
+                {
+                    ShrU32W(16)
+                        .Use(PT)
+                        .Use(orderingTicketValue),
+                    Iadd32i(0x200)
+                        .Use(PT)
+                        .Use(Lop32i(LogicOp.And, 0xfe00)
+                            .Use(PT)
+                            .Use(orderingTicketValue).Out),
+                    Iscadd(cc: true, 2, 0, 404)
+                        .Use(PT)
+                        .Use(Bfi(0x808)
+                            .Use(PT)
+                            .Use(affinityValue)
+                            .Use(Lop32i(LogicOp.And, 0xff)
+                                .Use(PT)
+                                .Use(orderingTicketValue).Out).Out),
+                    Iadd(x: true, 0, 405).Use(PT).Use(RZ),
+                    Ret().Use(PT)
+                };
+            }
+
+            public static IPatternTreeNode[] GetFsiIsLastWarpThread()
+            {
+                var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
+                var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
+
+                return new IPatternTreeNode[]
+                {
+                    IsetpU32(IComp.Eq)
+                        .Use(PT)
+                        .Use(PT)
+                        .Use(FloU32()
+                            .Use(PT)
+                            .Use(Vote(VoteMode.Any)
+                                .Use(PT)
+                                .Use(IsetpU32(IComp.Ne)
+                                    .Use(PT)
+                                    .Use(PT)
+                                    .Use(Lop(negB: true, LogicOp.PassB)
+                                        .Use(PT)
+                                        .Use(RZ)
+                                        .Use(threadKillValue).OutAt(1))
+                                    .Use(RZ).Out).OutAt(1)).Out)
+                        .Use(laneIdValue),
+                    Ret().Use(PT)
+                };
+            }
+
+            public static IPatternTreeNode[] GetFsiBeginPattern()
+            {
+                var addressLowValue = CallArg(1);
+
+                static PatternTreeNodeUse HighU16Equals(PatternTreeNodeUse x)
+                {
+                    var expectedValue = CallArg(3);
+
+                    return IsetpU32(IComp.Eq)
+                        .Use(PT)
+                        .Use(PT)
+                        .Use(ShrU32W(16).Use(PT).Use(x).Out)
+                        .Use(expectedValue).Out;
+                }
+
+                PatternTreeNode<byte> label;
+
+                return new IPatternTreeNode[]
+                {
+                    Cal(),
+                    Ret().Use(CallArg(0).Inv),
+                    Ret()
+                        .Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32)
+                            .Use(PT)
+                            .Use(addressLowValue).Out)),
+                    label = Label(),
+                    Bra()
+                        .Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32, 1)
+                            .Use(PT)
+                            .Use(addressLowValue).Out).Inv)
+                        .Use(label.Out),
+                    Ret().Use(PT)
+                };
+            }
+
+            public static IPatternTreeNode[] GetFsiEndPattern()
+            {
+                var voteResult = Vote(VoteMode.All).Use(PT).Use(PT).OutAt(1);
+                var popcResult = Popc().Use(PT).Use(voteResult).Out;
+                var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
+                var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
+
+                var addressLowValue = CallArg(1);
+                var incrementValue = CallArg(2);
+
+                return new IPatternTreeNode[]
+                {
+                    Cal(),
+                    Ret().Use(CallArg(0).Inv),
+                    Membar(Decoders.Membar.Vc).Use(PT),
+                    Ret().Use(IsetpU32(IComp.Ne)
+                        .Use(PT)
+                        .Use(PT)
+                        .Use(threadKillValue)
+                        .Use(RZ).Out),
+                    RedE(RedOp.Add, AtomSize.U32)
+                        .Use(IsetpU32(IComp.Eq)
+                            .Use(PT)
+                            .Use(PT)
+                            .Use(FloU32()
+                                .Use(PT)
+                                .Use(voteResult).Out)
+                            .Use(laneIdValue).Out)
+                        .Use(addressLowValue)
+                        .Use(Xmad(XmadCop.Cbcc, psl: true, hiloA: true, hiloB: true)
+                            .Use(PT)
+                            .Use(incrementValue)
+                            .Use(Xmad(XmadCop.Cfull, mrg: true, hiloB: true)
+                                .Use(PT)
+                                .Use(incrementValue)
+                                .Use(popcResult)
+                                .Use(RZ).Out)
+                            .Use(Xmad(XmadCop.Cfull)
+                                .Use(PT)
+                                .Use(incrementValue)
+                                .Use(popcResult)
+                                .Use(RZ).Out).Out),
+                    Ret().Use(PT)
+                };
+            }
+
+            private static PatternTreeNode<InstBfiI> Bfi(int imm)
+            {
+                return new(InstName.Bfi, (op) => !op.WriteCC && op.Imm20 == imm, isImm: true);
+            }
+
+            private static PatternTreeNode<InstBra> Bra()
+            {
+                return new(InstName.Bra, (op) => op.Ccc == Ccc.T && !op.Ca);
+            }
+
+            private static PatternTreeNode<InstCal> Cal()
+            {
+                return new(InstName.Cal, (op) => !op.Ca && op.Inc);
+            }
+
+            private static PatternTreeNode<InstFloR> FloU32()
+            {
+                return new(InstName.Flo, (op) => !op.Signed && !op.Sh && !op.NegB && !op.WriteCC);
+            }
+
+            private static PatternTreeNode<InstIaddC> Iadd(bool x, int cbufSlot, int cbufOffset)
+            {
+                return new(InstName.Iadd, (op) =>
+                    !op.Sat &&
+                    !op.WriteCC &&
+                    op.X == x &&
+                    op.AvgMode == AvgMode.NoNeg &&
+                    op.CbufSlot == cbufSlot &&
+                    op.CbufOffset == cbufOffset);
+            }
+
+            private static PatternTreeNode<InstIadd32i> Iadd32i(int imm)
+            {
+                return new(InstName.Iadd32i, (op) => !op.Sat && !op.WriteCC && !op.X && op.AvgMode == AvgMode.NoNeg && op.Imm32 == imm);
+            }
+
+            private static PatternTreeNode<InstIscaddR> Iscadd(bool cc, int imm)
+            {
+                return new(InstName.Iscadd, (op) => op.WriteCC == cc && op.AvgMode == AvgMode.NoNeg && op.Imm5 == imm);
+            }
+
+            private static PatternTreeNode<InstIscaddC> Iscadd(bool cc, int imm, int cbufSlot, int cbufOffset)
+            {
+                return new(InstName.Iscadd, (op) =>
+                    op.WriteCC == cc &&
+                    op.AvgMode == AvgMode.NoNeg &&
+                    op.Imm5 == imm &&
+                    op.CbufSlot == cbufSlot &&
+                    op.CbufOffset == cbufOffset);
+            }
+
+            private static PatternTreeNode<InstIsetpR> IsetpU32(IComp comp)
+            {
+                return new(InstName.Isetp, (op) => !op.Signed && op.IComp == comp && op.Bop == BoolOp.And);
+            }
+
+            private static PatternTreeNode<byte> Label()
+            {
+                return new(InstName.Invalid, (op) => true, type: TreeNodeType.Label);
+            }
+
+            private static PatternTreeNode<InstLopR> Lop(bool negB, LogicOp logicOp)
+            {
+                return new(InstName.Lop, (op) => !op.NegA && op.NegB == negB && !op.WriteCC && !op.X && op.Lop == logicOp && op.PredicateOp == PredicateOp.F);
+            }
+
+            private static PatternTreeNode<InstLop32i> Lop32i(LogicOp logicOp, int imm)
+            {
+                return new(InstName.Lop32i, (op) => !op.NegA && !op.NegB && !op.X && !op.WriteCC && op.LogicOp == logicOp && op.Imm32 == imm);
+            }
+
+            private static PatternTreeNode<InstMembar> Membar(Membar membar)
+            {
+                return new(InstName.Membar, (op) => op.Membar == membar);
+            }
+
+            private static PatternTreeNode<InstPopcR> Popc()
+            {
+                return new(InstName.Popc, (op) => !op.NegB);
+            }
+
+            private static PatternTreeNode<InstRet> Ret()
+            {
+                return new(InstName.Ret, (op) => op.Ccc == Ccc.T);
+            }
+
+            private static PatternTreeNode<InstS2r> S2r(SReg reg)
+            {
+                return new(InstName.S2r, (op) => op.SReg == reg);
+            }
+
+            private static PatternTreeNode<InstShrI> ShrU32W(int imm)
+            {
+                return new(InstName.Shr, (op) => !op.Signed && !op.Brev && op.M && op.XMode == 0 && op.Imm20 == imm, isImm: true);
+            }
+
+            private static PatternTreeNode<InstLdg> LdgE(CacheOpLd cacheOp, LsSize size, byte order = 0)
+            {
+                return new(InstName.Ldg, (op) => op.E && op.CacheOp == cacheOp && op.LsSize == size, order: order);
+            }
+
+            private static PatternTreeNode<InstRed> RedE(RedOp redOp, AtomSize size, byte order = 0)
+            {
+                return new(InstName.Red, (op) => op.E && op.RedOp == redOp && op.RedSize == size, order: order);
+            }
+
+            private static PatternTreeNode<InstVote> Vote(VoteMode mode)
+            {
+                return new(InstName.Vote, (op) => op.VoteMode == mode);
+            }
+
+            private static PatternTreeNode<InstXmadR> Xmad(XmadCop cop, bool psl = false, bool mrg = false, bool hiloA = false, bool hiloB = false)
+            {
+                return new(InstName.Xmad, (op) => op.XmadCop == cop && op.Psl == psl && op.Mrg == mrg && op.HiloA == hiloA && op.HiloB == hiloB);
+            }
+
+            private static PatternTreeNodeUse PT => PTOrRZ();
+            private static PatternTreeNodeUse RZ => PTOrRZ();
+            private static PatternTreeNodeUse Undef => new PatternTreeNodeUse(0, null);
+
+            private static PatternTreeNodeUse CallArg(int index)
+            {
+                return new PatternTreeNodeUse(-(index + 2), null);
+            }
+
+            private static PatternTreeNodeUse PTOrRZ()
+            {
+                return new PatternTreeNodeUse(-1, null);
+            }
+        }
+
+        private static void PrintTreeNode(TreeNode node, string indentation)
+        {
+            Console.WriteLine($" {node.Op.Name}");
+
+            for (int i = 0; i < node.Uses.Count; i++)
+            {
+                TreeNodeUse use = node.Uses[i];
+                bool last = i == node.Uses.Count - 1;
+                char separator = last ? '`' : '|';
+
+                if (use.Node != null)
+                {
+                    Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
+                    PrintTreeNode(use.Node, indentation + (last ? "       " : " |     "));
+                }
+                else
+                {
+                    Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
+                }
+            }
+        }
+
+        private static void PrintTreeNode(IPatternTreeNode node, string indentation)
+        {
+            Console.WriteLine($" {node.Name}");
+
+            for (int i = 0; i < node.Uses.Count; i++)
+            {
+                PatternTreeNodeUse use = node.Uses[i];
+                bool last = i == node.Uses.Count - 1;
+                char separator = last ? '`' : '|';
+
+                if (use.Node != null)
+                {
+                    Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
+                    PrintTreeNode(use.Node, indentation + (last ? "       " : " |     "));
+                }
+                else
+                {
+                    Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
+                }
+            }
+        }
+    }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index ec7e898237..2314016e2f 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -315,15 +315,16 @@ namespace Ryujinx.Graphics.Shader.Translation
             bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
             bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
             bool accurateType = inst != Instruction.Lod;
+            bool coherent = flags.HasFlag(TextureFlags.Coherent);
 
             if (isImage)
             {
-                SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false);
+                SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false, coherent);
             }
             else
             {
                 bool intCoords = flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
-                SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType);
+                SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType, coherent);
             }
         }
 
@@ -335,7 +336,8 @@ namespace Ryujinx.Graphics.Shader.Translation
             TextureFormat format,
             bool intCoords,
             bool write,
-            bool accurateType)
+            bool accurateType,
+            bool coherent)
         {
             var dimensions = type.GetDimensions();
             var isIndexed = type.HasFlag(SamplerType.Indexed);
@@ -361,6 +363,11 @@ namespace Ryujinx.Graphics.Shader.Translation
                 usageFlags |= TextureUsageFlags.ImageStore;
             }
 
+            if (coherent)
+            {
+                usageFlags |= TextureUsageFlags.ImageCoherent;
+            }
+
             int arraySize = isIndexed ? SamplerArraySize : 1;
 
             for (int layer = 0; layer < arraySize; layer++)
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 0243eba139..a658697b7f 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -4,7 +4,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
 using Ryujinx.Graphics.Shader.StructuredIr;
 using Ryujinx.Graphics.Shader.Translation.Optimizations;
 using System;
-using System.Collections.Generic;
+using System.Linq;
 using System.Numerics;
 
 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -33,9 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         {
             counts ??= new TranslationCounts();
 
-            Block[][] cfg = DecodeShader(address, gpuAccessor, options, counts, out ShaderConfig config);
-
-            return new TranslatorContext(address, cfg, config);
+            return DecodeShader(address, gpuAccessor, options, counts);
         }
 
         internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo)
@@ -112,35 +110,29 @@ namespace Ryujinx.Graphics.Shader.Translation
             return program;
         }
 
-        private static Block[][] DecodeShader(
-            ulong address,
-            IGpuAccessor gpuAccessor,
-            TranslationOptions options,
-            TranslationCounts counts,
-            out ShaderConfig config)
+        private static TranslatorContext DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationOptions options, TranslationCounts counts)
         {
-            Block[][] cfg;
+            ShaderConfig config;
+            DecodedProgram program;
             ulong maxEndAddress = 0;
 
             if ((options.Flags & TranslationFlags.Compute) != 0)
             {
                 config = new ShaderConfig(gpuAccessor, options, counts);
 
-                cfg = Decoder.Decode(config, address);
+                program = Decoder.Decode(config, address);
             }
             else
             {
                 config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, options, counts);
 
-                cfg = Decoder.Decode(config, address + HeaderSize);
+                program = Decoder.Decode(config, address + HeaderSize);
             }
 
-            for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
+            foreach (DecodedFunction function in program)
             {
-                for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
+                foreach (Block block in function.Blocks)
                 {
-                    Block block = cfg[funcIndex][blkIndex];
-
                     if (maxEndAddress < block.EndAddress)
                     {
                         maxEndAddress = block.EndAddress;
@@ -164,36 +156,36 @@ namespace Ryujinx.Graphics.Shader.Translation
 
             config.SizeAdd((int)maxEndAddress + (options.Flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize));
 
-            return cfg;
+            return new TranslatorContext(address, program, config);
         }
 
-        internal static FunctionCode[] EmitShader(Block[][] cfg, ShaderConfig config, bool initializeOutputs, out int initializationOperations)
+        internal static FunctionCode[] EmitShader(DecodedProgram program, ShaderConfig config, bool initializeOutputs, out int initializationOperations)
         {
             initializationOperations = 0;
 
-            Dictionary<ulong, int> funcIds = new Dictionary<ulong, int>();
+            FunctionMatch.RunPass(program);
 
-            for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
+            foreach (DecodedFunction function in program.OrderBy(x => x.Address).Where(x => !x.IsCompilerGenerated))
             {
-                funcIds.Add(cfg[funcIndex][0].Address, funcIndex);
+                program.AddFunctionAndSetId(function);
             }
 
-            List<FunctionCode> funcs = new List<FunctionCode>();
+            FunctionCode[] functions = new FunctionCode[program.FunctionsWithIdCount];
 
-            for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
+            for (int index = 0; index < functions.Length; index++)
             {
-                EmitterContext context = new EmitterContext(config, funcIndex != 0, funcIds);
+                EmitterContext context = new EmitterContext(program, config, index != 0);
 
-                if (initializeOutputs && funcIndex == 0)
+                if (initializeOutputs && index == 0)
                 {
                     EmitOutputsInitialization(context, config);
                     initializationOperations = context.OperationsCount;
                 }
 
-                for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
-                {
-                    Block block = cfg[funcIndex][blkIndex];
+                DecodedFunction function = program.GetFunctionById(index);
 
+                foreach (Block block in function.Blocks)
+                {
                     context.CurrBlock = block;
 
                     context.MarkLabel(context.GetLabel(block.Address));
@@ -201,10 +193,10 @@ namespace Ryujinx.Graphics.Shader.Translation
                     EmitOps(context, block);
                 }
 
-                funcs.Add(new FunctionCode(context.GetOperations()));
+                functions[index] = new FunctionCode(context.GetOperations());
             }
 
-            return funcs.ToArray();
+            return functions;
         }
 
         private static void EmitOutputsInitialization(EmitterContext context, ShaderConfig config)
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
index 34b116d6b5..b19e39af76 100644
--- a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 {
     public class TranslatorContext
     {
-        private readonly Block[][] _cfg;
+        private readonly DecodedProgram _program;
         private ShaderConfig _config;
 
         public ulong Address { get; }
@@ -23,11 +23,11 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public IGpuAccessor GpuAccessor => _config.GpuAccessor;
 
-        internal TranslatorContext(ulong address, Block[][] cfg, ShaderConfig config)
+        internal TranslatorContext(ulong address, DecodedProgram program, ShaderConfig config)
         {
             Address = address;
+            _program = program;
             _config = config;
-            _cfg    = cfg;
         }
 
         private static bool IsUserAttribute(Operand operand)
@@ -141,13 +141,13 @@ namespace Ryujinx.Graphics.Shader.Translation
                     nextStage._config.UsedInputAttributesPerPatch);
             }
 
-            FunctionCode[] code = EmitShader(_cfg, _config, initializeOutputs: other == null, out _);
+            FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
 
             if (other != null)
             {
                 other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, 0);
 
-                FunctionCode[] otherCode = EmitShader(other._cfg, other._config, initializeOutputs: true, out int aStart);
+                FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
 
                 code = Combine(otherCode, code, aStart);