diff --git a/ChocolArm64/Decoder/ABlock.cs b/ChocolArm64/Decoder/ABlock.cs
index 32974c1abf..7a0fc60773 100644
--- a/ChocolArm64/Decoder/ABlock.cs
+++ b/ChocolArm64/Decoder/ABlock.cs
@@ -5,7 +5,7 @@ namespace ChocolArm64.Decoder
     class ABlock
     {
         public long Position    { get; set; }
-        public long EndPosition { get; set; }       
+        public long EndPosition { get; set; }
 
         public ABlock Next   { get; set; }
         public ABlock Branch { get; set; }
diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs
index 32a68ad34d..b154a54cd2 100644
--- a/ChocolArm64/Decoder/ADecoder.cs
+++ b/ChocolArm64/Decoder/ADecoder.cs
@@ -94,7 +94,7 @@ namespace ChocolArm64.Decoder
                     }
                 }
 
-                //If we have on the tree two blocks with the same end position,
+                //If we have on the graph two blocks with the same end position,
                 //then we need to split the bigger block and have two small blocks,
                 //the end position of the bigger "Current" block should then be == to
                 //the position of the "Smaller" block.
diff --git a/Ryujinx.Core/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs
index f3e41046ae..0c1c83d5d3 100644
--- a/Ryujinx.Core/Gpu/TextureReader.cs
+++ b/Ryujinx.Core/Gpu/TextureReader.cs
@@ -10,19 +10,132 @@ namespace Ryujinx.Core.Gpu
         {
             switch (Texture.Format)
             {
-                case GalTextureFormat.A8B8G8R8: return Read4Bpp    (Memory, Texture);
-                case GalTextureFormat.A1B5G5R5: return Read2Bpp    (Memory, Texture);
-                case GalTextureFormat.B5G6R5:   return Read2Bpp    (Memory, Texture);
-                case GalTextureFormat.BC1:      return Read8Bpt4x4 (Memory, Texture);
-                case GalTextureFormat.BC2:      return Read16Bpt4x4(Memory, Texture);
-                case GalTextureFormat.BC3:      return Read16Bpt4x4(Memory, Texture);
-                case GalTextureFormat.BC4:      return Read8Bpt4x4 (Memory, Texture);
-                case GalTextureFormat.BC5:      return Read16Bpt4x4(Memory, Texture);
+                case GalTextureFormat.R32G32B32A32: return Read16Bpp   (Memory, Texture);
+                case GalTextureFormat.R16G16B16A16: return Read8Bpp    (Memory, Texture);
+                case GalTextureFormat.A8B8G8R8:     return Read4Bpp    (Memory, Texture);
+                case GalTextureFormat.R32:          return Read4Bpp    (Memory, Texture);
+                case GalTextureFormat.A1B5G5R5:     return Read5551    (Memory, Texture);
+                case GalTextureFormat.B5G6R5:       return Read565     (Memory, Texture);
+                case GalTextureFormat.G8R8:         return Read2Bpp    (Memory, Texture);
+                case GalTextureFormat.R8:           return Read1Bpp    (Memory, Texture);
+                case GalTextureFormat.BC1:          return Read8Bpt4x4 (Memory, Texture);
+                case GalTextureFormat.BC2:          return Read16Bpt4x4(Memory, Texture);
+                case GalTextureFormat.BC3:          return Read16Bpt4x4(Memory, Texture);
+                case GalTextureFormat.BC4:          return Read8Bpt4x4 (Memory, Texture);
+                case GalTextureFormat.BC5:          return Read16Bpt4x4(Memory, Texture);
             }
 
             throw new NotImplementedException(Texture.Format.ToString());
         }
 
+        private unsafe static byte[] Read1Bpp(IAMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height];
+
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 1);
+
+            (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
+                Memory,
+                Texture.Position);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    byte Pixel = CpuMem.ReadByteUnchecked(Position + Offset);
+
+                    *(BuffPtr + OutOffs) = Pixel;
+
+                    OutOffs++;
+                }
+            }
+
+            return Output;
+        }
+
+        private unsafe static byte[] Read5551(IAMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height * 2];
+
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
+
+            (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
+                Memory,
+                Texture.Position);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    uint Pixel = (uint)CpuMem.ReadInt16Unchecked(Position + Offset);
+
+                    Pixel = (Pixel & 0x001f) << 11 |
+                            (Pixel & 0x03e0) << 1  |
+                            (Pixel & 0x7c00) >> 9  |
+                            (Pixel & 0x8000) >> 15;
+
+                    *(short*)(BuffPtr + OutOffs) = (short)Pixel;
+
+                    OutOffs += 2;
+                }
+            }
+
+            return Output;
+        }
+
+        private unsafe static byte[] Read565(IAMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height * 2];
+
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2);
+
+            (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
+                Memory,
+                Texture.Position);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    uint Pixel = (uint)CpuMem.ReadInt16Unchecked(Position + Offset);
+
+                    Pixel = (Pixel & 0x001f) << 11 |
+                            (Pixel & 0x07e0)       |
+                            (Pixel & 0xf800) >> 11;
+
+                    *(short*)(BuffPtr + OutOffs) = (short)Pixel;
+
+                    OutOffs += 2;
+                }
+            }
+
+            return Output;
+        }
+
         private unsafe static byte[] Read2Bpp(IAMemory Memory, Texture Texture)
         {
             int Width  = Texture.Width;
@@ -89,6 +202,74 @@ namespace Ryujinx.Core.Gpu
             return Output;
         }
 
+        private unsafe static byte[] Read8Bpp(IAMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height * 8];
+
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8);
+
+            (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
+                Memory,
+                Texture.Position);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    long Pixel = CpuMem.ReadInt64Unchecked(Position + Offset);
+
+                    *(long*)(BuffPtr + OutOffs) = Pixel;
+
+                    OutOffs += 8;
+                }
+            }
+
+            return Output;
+        }
+
+        private unsafe static byte[] Read16Bpp(IAMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height * 16];
+
+            ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16);
+
+            (AMemory CpuMem, long Position) = TextureHelper.GetMemoryAndPosition(
+                Memory,
+                Texture.Position);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    long PxLow  = CpuMem.ReadInt64Unchecked(Position + Offset + 0);
+                    long PxHigh = CpuMem.ReadInt64Unchecked(Position + Offset + 8);
+
+                    *(long*)(BuffPtr + OutOffs + 0) = PxLow;
+                    *(long*)(BuffPtr + OutOffs + 8) = PxHigh;
+
+                    OutOffs += 16;
+                }
+            }
+
+            return Output;
+        }
+
         private unsafe static byte[] Read8Bpt4x4(IAMemory Memory, Texture Texture)
         {
             int Width  = (Texture.Width  + 3) / 4;
diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
index 37291e18bf..b3d8b03d9e 100644
--- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs
+++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
@@ -2,13 +2,18 @@ namespace Ryujinx.Graphics.Gal
 {
     public enum GalTextureFormat
     {
-        A8B8G8R8 = 0x8,
-        A1B5G5R5 = 0x14,
-        B5G6R5   = 0x15,
-        BC1      = 0x24,
-        BC2      = 0x25,
-        BC3      = 0x26,
-        BC4      = 0x27,
-        BC5      = 0x28
+        R32G32B32A32 = 0x1,
+        R16G16B16A16 = 0x3,
+        A8B8G8R8     = 0x8,
+        R32          = 0xf,
+        A1B5G5R5     = 0x14,
+        B5G6R5       = 0x15,
+        G8R8         = 0x18,
+        R8           = 0x1d,
+        BC1          = 0x24,
+        BC2          = 0x25,
+        BC3          = 0x26,
+        BC4          = 0x27,
+        BC5          = 0x28
     }
 }
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index d266a87a8e..ee697097f0 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -59,9 +59,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
         {
             switch (Format)
             {
-                case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
-                case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
-                case GalTextureFormat.B5G6R5:   return (PixelFormat.Rgb,  PixelType.UnsignedShort565);
+                case GalTextureFormat.R32G32B32A32: return (PixelFormat.Rgba, PixelType.Float);
+                case GalTextureFormat.R16G16B16A16: return (PixelFormat.Rgba, PixelType.HalfFloat);
+                case GalTextureFormat.A8B8G8R8:     return (PixelFormat.Rgba, PixelType.UnsignedByte);
+                case GalTextureFormat.R32:          return (PixelFormat.Red,  PixelType.Float);
+                case GalTextureFormat.A1B5G5R5:     return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
+                case GalTextureFormat.B5G6R5:       return (PixelFormat.Rgb,  PixelType.UnsignedShort565);
+                case GalTextureFormat.G8R8:         return (PixelFormat.Rg,   PixelType.UnsignedByte);
+                case GalTextureFormat.R8:           return (PixelFormat.Red,  PixelType.UnsignedByte);
             }
 
             throw new NotImplementedException(Format.ToString());
@@ -145,20 +150,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
         {
             switch (BlendEquation)
             {
+                default:
                 case GalBlendEquation.FuncAdd:             return BlendEquationMode.FuncAdd;
                 case GalBlendEquation.FuncSubtract:        return BlendEquationMode.FuncSubtract;
                 case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract;
                 case GalBlendEquation.Min:                 return BlendEquationMode.Min;
                 case GalBlendEquation.Max:                 return BlendEquationMode.Max;
             }
-
-            throw new ArgumentException(nameof(BlendEquation));
         }
 
         public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
         {
             switch (BlendFactor)
             {
+                default:
                 case GalBlendFactor.Zero:                  return BlendingFactorSrc.Zero;
                 case GalBlendFactor.One:                   return BlendingFactorSrc.One;
                 case GalBlendFactor.SrcColor:              return BlendingFactorSrc.SrcColor;
@@ -179,14 +184,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                 case GalBlendFactor.Src1Alpha:             return BlendingFactorSrc.Src1Alpha;
                 case GalBlendFactor.OneMinusSrc1Alpha:     return BlendingFactorSrc.OneMinusSrc1Alpha;
             }
-
-            throw new ArgumentException(nameof(BlendFactor));
         }
 
         public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
         {
             switch (BlendFactor)
             {
+                default:
                 case GalBlendFactor.Zero:                  return BlendingFactorDest.Zero;
                 case GalBlendFactor.One:                   return BlendingFactorDest.One;
                 case GalBlendFactor.SrcColor:              return BlendingFactorDest.SrcColor;
@@ -207,8 +211,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                 case GalBlendFactor.Src1Alpha:             return BlendingFactorDest.Src1Alpha;
                 case GalBlendFactor.OneMinusSrc1Alpha:     return BlendingFactorDest.OneMinusSrc1Alpha;
             }
-
-            throw new ArgumentException(nameof(BlendFactor));
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index 2650569e6c..43a04813c7 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -4,6 +4,10 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     class GlslDecl
     {
+        public const int TessCoordAttrX  = 0x2f0;
+        public const int TessCoordAttrY  = 0x2f4;
+        public const int TessCoordAttrZ  = 0x2f8;
+        public const int InstanceIdAttr  = 0x2f8;
         public const int VertexIdAttr    = 0x2fc;
         public const int GlPositionWAttr = 0x7c;
 
@@ -48,7 +52,7 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public GalShaderType ShaderType { get; private set; }
 
-        public GlslDecl(ShaderIrNode[] Nodes, GalShaderType ShaderType)
+        public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType)
         {
             this.ShaderType = ShaderType;
 
@@ -75,9 +79,12 @@ namespace Ryujinx.Graphics.Gal.Shader
                 m_OutAttributes.Add(7, new ShaderDeclInfo("gl_Position", -1, 0, 4));
             }
 
-            foreach (ShaderIrNode Node in Nodes)
+            foreach (ShaderIrBlock Block in Blocks)
             {
-                Traverse(null, Node);
+                foreach (ShaderIrNode Node in Block.GetNodes())
+                {
+                    Traverse(null, Node);
+                }
             }
         }
 
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 88e462439c..5c4537fe05 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -25,6 +25,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private GlslDecl Decl;
 
+        private ShaderIrBlock[] Blocks;
+
         private StringBuilder SB;
 
         public GlslDecompiler()
@@ -37,6 +39,8 @@ namespace Ryujinx.Graphics.Gal.Shader
                 { ShaderIrInst.Asr,    GetAsrExpr    },
                 { ShaderIrInst.Band,   GetBandExpr   },
                 { ShaderIrInst.Bnot,   GetBnotExpr   },
+                { ShaderIrInst.Bor,    GetBorExpr    },
+                { ShaderIrInst.Bxor,   GetBxorExpr   },
                 { ShaderIrInst.Ceil,   GetCeilExpr   },
                 { ShaderIrInst.Ceq,    GetCeqExpr    },
                 { ShaderIrInst.Cge,    GetCgeExpr    },
@@ -50,19 +54,27 @@ namespace Ryujinx.Graphics.Gal.Shader
                 { ShaderIrInst.Fabs,   GetAbsExpr    },
                 { ShaderIrInst.Fadd,   GetAddExpr    },
                 { ShaderIrInst.Fceq,   GetCeqExpr    },
+                { ShaderIrInst.Fcequ,  GetCequExpr   },
                 { ShaderIrInst.Fcge,   GetCgeExpr    },
+                { ShaderIrInst.Fcgeu,  GetCgeuExpr   },
                 { ShaderIrInst.Fcgt,   GetCgtExpr    },
+                { ShaderIrInst.Fcgtu,  GetCgtuExpr   },
                 { ShaderIrInst.Fclamp, GetFclampExpr },
                 { ShaderIrInst.Fcle,   GetCleExpr    },
+                { ShaderIrInst.Fcleu,  GetCleuExpr   },
                 { ShaderIrInst.Fclt,   GetCltExpr    },
+                { ShaderIrInst.Fcltu,  GetCltuExpr   },
+                { ShaderIrInst.Fcnan,  GetCnanExpr   },
                 { ShaderIrInst.Fcne,   GetCneExpr    },
+                { ShaderIrInst.Fcneu,  GetCneuExpr   },
+                { ShaderIrInst.Fcnum,  GetCnumExpr   },
                 { ShaderIrInst.Fcos,   GetFcosExpr   },
                 { ShaderIrInst.Fex2,   GetFex2Expr   },
                 { ShaderIrInst.Ffma,   GetFfmaExpr   },
                 { ShaderIrInst.Flg2,   GetFlg2Expr   },
                 { ShaderIrInst.Floor,  GetFloorExpr  },
-                { ShaderIrInst.Fmax,   GetFmaxExpr   },
-                { ShaderIrInst.Fmin,   GetFminExpr   },
+                { ShaderIrInst.Fmax,   GetMaxExpr    },
+                { ShaderIrInst.Fmin,   GetMinExpr    },
                 { ShaderIrInst.Fmul,   GetMulExpr    },
                 { ShaderIrInst.Fneg,   GetNegExpr    },
                 { ShaderIrInst.Frcp,   GetFrcpExpr   },
@@ -74,6 +86,8 @@ namespace Ryujinx.Graphics.Gal.Shader
                 { ShaderIrInst.Kil,    GetKilExpr    },
                 { ShaderIrInst.Lsl,    GetLslExpr    },
                 { ShaderIrInst.Lsr,    GetLsrExpr    },
+                { ShaderIrInst.Max,    GetMaxExpr    },
+                { ShaderIrInst.Min,    GetMinExpr    },
                 { ShaderIrInst.Mul,    GetMulExpr    },
                 { ShaderIrInst.Neg,    GetNegExpr    },
                 { ShaderIrInst.Not,    GetNotExpr    },
@@ -91,11 +105,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType)
         {
-            ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Memory, Position);
+            Blocks = ShaderDecoder.Decode(Memory, Position);
 
-            ShaderIrNode[] Nodes = Block.GetNodes();
-
-            Decl = new GlslDecl(Nodes, ShaderType);
+            Decl = new GlslDecl(Blocks, ShaderType);
 
             SB = new StringBuilder();
 
@@ -108,7 +120,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             PrintDeclGprs();
             PrintDeclPreds();
 
-            PrintBlockScope(Nodes, 0, Nodes.Length, "void main()", 1);
+            PrintBlockScope(Blocks[0], null, null, "void main()", IdentationStr);
 
             string GlslCode = SB.ToString();
 
@@ -230,37 +242,75 @@ namespace Ryujinx.Graphics.Gal.Shader
         }
 
         private void PrintBlockScope(
-            ShaderIrNode[] Nodes,
-            int            Start,
-            int            Count,
-            string         ScopeName,
-            int            IdentationLevel)
+            ShaderIrBlock Block,
+            ShaderIrBlock EndBlock,
+            ShaderIrBlock LoopBlock,
+            string        ScopeName,
+            string        Identation,
+            bool          IsDoWhile = false)
         {
-            string Identation = string.Empty;
+            string UpIdent = Identation.Substring(0, Identation.Length - IdentationStr.Length);
 
-            for (int Index = 0; Index < IdentationLevel - 1; Index++)
+            if (IsDoWhile)
             {
-                Identation += IdentationStr;
+                SB.AppendLine(UpIdent + "do {");
+            }
+            else
+            {
+                SB.AppendLine(UpIdent + ScopeName + " {");
             }
 
-            if (ScopeName != string.Empty)
+            while (Block != null && Block != EndBlock)
             {
-                ScopeName += " ";
+                ShaderIrNode[] Nodes = Block.GetNodes();
+
+                Block = PrintNodes(Block, EndBlock, LoopBlock, Identation, Nodes);
             }
 
-            SB.AppendLine(Identation + ScopeName + "{");
-
-            string LastLine = Identation + "}";
-
-            if (IdentationLevel > 0)
+            if (IsDoWhile)
             {
-                Identation += IdentationStr;
+                SB.AppendLine(UpIdent + "} " + ScopeName + ";");
+            }
+            else
+            {
+                SB.AppendLine(UpIdent + "}");
+            }
+        }
+
+        private ShaderIrBlock PrintNodes(
+            ShaderIrBlock         Block,
+            ShaderIrBlock         EndBlock,
+            ShaderIrBlock         LoopBlock,
+            string                Identation,
+            params ShaderIrNode[] Nodes)
+        {
+            /*
+             * Notes about control flow and if-else/loop generation:
+             * The code assumes that the program has sane control flow,
+             * that is, there's no jumps to a location after another jump or
+             * jump target (except for the end of an if-else block), and backwards
+             * jumps to a location before the last loop dominator.
+             * Such cases needs to be transformed on a step before the GLSL code
+             * generation to ensure that we have sane graphs to work with.
+             * TODO: Such transformation is not yet implemented.
+             */
+            string NewIdent = Identation + IdentationStr;
+
+            ShaderIrBlock LoopTail = GetLoopTailBlock(Block);
+
+            if (LoopTail != null && LoopBlock != Block)
+            {
+                //Shoock! kuma shock! We have a loop here!
+                //The entire sequence needs to be inside a do-while block.
+                ShaderIrBlock LoopEnd = GetDownBlock(LoopTail);
+
+                PrintBlockScope(Block, LoopEnd, Block, "while (false)", NewIdent, IsDoWhile: true);
+
+                return LoopEnd;
             }
 
-            for (int Index = Start; Index < Start + Count; Index++)
+            foreach (ShaderIrNode Node in Nodes)
             {
-                ShaderIrNode Node = Nodes[Index];
-
                 if (Node is ShaderIrCond Cond)
                 {
                     string IfExpr = GetSrcExpr(Cond.Pred, true);
@@ -272,42 +322,41 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                     if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
                     {
-                        ShaderIrLabel Label = (ShaderIrLabel)Op.OperandA;
+                        //Branch is a loop branch and would result in infinite recursion.
+                        if (Block.Branch.Position <= Block.Position)
+                        {
+                            SB.AppendLine(Identation + "if (" + IfExpr + ") {");
 
-                        int Target = FindLabel(Nodes, Label, Index + 1);
+                            SB.AppendLine(Identation + IdentationStr + "continue;");
 
-                        int IfCount = Target - Index - 1;
+                            SB.AppendLine(Identation + "}");
+
+                            continue;
+                        }
 
                         string SubScopeName = "if (!" + IfExpr + ")";
 
-                        if (Nodes[Index + IfCount] is ShaderIrOp LastOp && LastOp.Inst == ShaderIrInst.Bra)
+                        PrintBlockScope(Block.Next, Block.Branch, LoopBlock, SubScopeName, NewIdent);
+
+                        ShaderIrBlock IfElseEnd = GetUpBlock(Block.Branch).Branch;
+
+                        if (IfElseEnd?.Position > Block.Branch.Position)
                         {
-                            Target = FindLabel(Nodes, (ShaderIrLabel)LastOp.OperandA, Index + 1);
+                            PrintBlockScope(Block.Branch, IfElseEnd, LoopBlock, "else", NewIdent);
 
-                            int ElseCount = Target - (Index + 1 + IfCount);
-
-                            PrintBlockScope(Nodes, Index + 1, IfCount - 1, SubScopeName, IdentationLevel + 1);
-
-                            PrintBlockScope(Nodes, Index + 1 + IfCount, ElseCount, "else", IdentationLevel + 1);
-
-                            Index += IfCount + ElseCount;
+                            return IfElseEnd;
                         }
-                        else
-                        {
-                            PrintBlockScope(Nodes, Index + 1, IfCount, SubScopeName, IdentationLevel + 1);
 
-                            Index += IfCount;
-                        }
+                        return Block.Branch;
                     }
                     else
                     {
-                        string SubScopeName = "if (" + IfExpr + ")";
+                        SB.AppendLine(Identation + "if (" + IfExpr + ") {");
 
-                        ShaderIrNode[] Child = new ShaderIrNode[] { Cond.Child };
+                        PrintNodes(Block, EndBlock, LoopBlock, NewIdent, Cond.Child);
 
-                        PrintBlockScope(Child, 0, 1, SubScopeName, IdentationLevel + 1);
+                        SB.AppendLine(Identation + "}");
                     }
-
                 }
                 else if (Node is ShaderIrAsg Asg)
                 {
@@ -322,7 +371,16 @@ namespace Ryujinx.Graphics.Gal.Shader
                 }
                 else if (Node is ShaderIrOp Op)
                 {
-                    if (Op.Inst == ShaderIrInst.Exit)
+                    if (Op.Inst == ShaderIrInst.Bra)
+                    {
+                        if (Block.Branch.Position <= Block.Position)
+                        {
+                            SB.AppendLine(Identation + "continue;");
+                        }
+
+                        continue;
+                    }
+                    else if (Op.Inst == ShaderIrInst.Exit)
                     {
                         //Do everything that needs to be done before
                         //the shader ends here.
@@ -336,10 +394,6 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                     SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
                 }
-                else if (Node is ShaderIrLabel Label)
-                {
-                    //TODO: Add support for loops here.
-                }
                 else if (Node is ShaderIrCmnt Cmnt)
                 {
                     SB.AppendLine(Identation + "// " + Cmnt.Comment);
@@ -350,22 +404,35 @@ namespace Ryujinx.Graphics.Gal.Shader
                 }
             }
 
-            SB.AppendLine(LastLine);
+            return Block.Next;
         }
 
-        private int FindLabel(ShaderIrNode[] Nodes, ShaderIrLabel Label, int Start)
+        private ShaderIrBlock GetUpBlock(ShaderIrBlock Block)
         {
-            int Target;
+            return Blocks.FirstOrDefault(x => x.EndPosition == Block.Position);
+        }
 
-            for (Target = Start; Target < Nodes.Length; Target++)
+        private ShaderIrBlock GetDownBlock(ShaderIrBlock Block)
+        {
+            return Blocks.FirstOrDefault(x => x.Position == Block.EndPosition);
+        }
+
+        private ShaderIrBlock GetLoopTailBlock(ShaderIrBlock LoopHead)
+        {
+            ShaderIrBlock Tail = null;
+
+            foreach (ShaderIrBlock Block in LoopHead.Sources)
             {
-                if (Nodes[Target] == Label)
+                if (Block.Position >= LoopHead.Position)
                 {
-                    return Target;
+                    if (Tail == null || Tail.Position < Block.Position)
+                    {
+                        Tail = Block;
+                    }
                 }
             }
 
-            throw new InvalidOperationException();
+            return Tail;
         }
 
         private bool IsValidOutOper(ShaderIrNode Node)
@@ -480,9 +547,22 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetName(ShaderIrOperAbuf Abuf)
         {
-            if (Abuf.Offs == GlslDecl.VertexIdAttr)
+            if (Decl.ShaderType == GalShaderType.Vertex)
             {
-                return "gl_VertexID";
+                switch (Abuf.Offs)
+                {
+                    case GlslDecl.VertexIdAttr:   return "gl_VertexID";
+                    case GlslDecl.InstanceIdAttr: return "gl_InstanceID";
+                }
+            }
+            else if (Decl.ShaderType == GalShaderType.TessEvaluation)
+            {
+                switch (Abuf.Offs)
+                {
+                    case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x";
+                    case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y";
+                    case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z";
+                }
             }
 
             return GetName(Decl.InAttributes, Abuf);
@@ -567,6 +647,10 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
 
+        private string GetBorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "||");
+
+        private string GetBxorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "^^");
+
         private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil");
 
         private string GetClampsExpr(ShaderIrOp Op)
@@ -583,13 +667,34 @@ namespace Ryujinx.Graphics.Gal.Shader
                              "uint(" + GetOperExpr(Op, Op.OperandC) + ")))";
         }
 
-        private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
         private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
-        private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
-        private string GetCgtExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">");
-        private string GetCneExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "!=");
+
+        private string GetCequExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "==");
+
         private string GetCgeExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">=");
 
+        private string GetCgeuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, ">=");
+
+        private string GetCgtExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">");
+
+        private string GetCgtuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, ">");
+
+        private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
+
+        private string GetCleuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "<=");
+
+        private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
+
+        private string GetCltuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "<");
+
+        private string GetCnanExpr(ShaderIrOp Op) => GetUnaryCall(Op, "isnan");
+
+        private string GetCneExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "!=");
+
+        private string GetCneuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "!=");
+
+        private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
+
         private string GetExitExpr(ShaderIrOp Op) => "return";
 
         private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
@@ -604,9 +709,6 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
 
-        private string GetFmaxExpr(ShaderIrOp Op) => GetBinaryCall(Op, "max");
-        private string GetFminExpr(ShaderIrOp Op) => GetBinaryCall(Op, "min");
-
         private string GetFrcpExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "1 / ");
 
         private string GetFrsqExpr(ShaderIrOp Op) => GetUnaryCall(Op, "inversesqrt");
@@ -634,6 +736,9 @@ namespace Ryujinx.Graphics.Gal.Shader
                                  GetOperExpr(Op, Op.OperandB) + ")";
         }
 
+        private string GetMaxExpr(ShaderIrOp Op) => GetBinaryCall(Op, "max");
+        private string GetMinExpr(ShaderIrOp Op) => GetBinaryCall(Op, "min");
+
         private string GetMulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
 
         private string GetNegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
@@ -733,6 +838,18 @@ namespace Ryujinx.Graphics.Gal.Shader
                    GetOperExpr(Op, Op.OperandB);
         }
 
+        private string GetBinaryExprWithNaN(ShaderIrOp Op, string Opr)
+        {
+            string A = GetOperExpr(Op, Op.OperandA);
+            string B = GetOperExpr(Op, Op.OperandB);
+
+            string NaNCheck =
+                " || isnan(" + A + ")" +
+                " || isnan(" + B + ")";
+
+            return A + " " + Opr + " " + B + NaNCheck;
+        }
+
         private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2)
         {
             return GetOperExpr(Op, Op.OperandA) + " " + Opr1 + " " +
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 1bb5f47808..ddd3e3e8c5 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -126,6 +126,21 @@ namespace Ryujinx.Graphics.Gal.Shader
             EmitFsetp(Block, OpCode, ShaderOper.RR);
         }
 
+        public static void Imnmx_C(ShaderIrBlock Block, long OpCode)
+        {
+            EmitImnmx(Block, OpCode, ShaderOper.CR);
+        }
+
+        public static void Imnmx_I(ShaderIrBlock Block, long OpCode)
+        {
+            EmitImnmx(Block, OpCode, ShaderOper.Imm);
+        }
+
+        public static void Imnmx_R(ShaderIrBlock Block, long OpCode)
+        {
+            EmitImnmx(Block, OpCode, ShaderOper.RR);
+        }
+
         public static void Ipa(ShaderIrBlock Block, long OpCode)
         {
             ShaderIrNode OperA = GetOperAbuf28(OpCode);
@@ -265,6 +280,26 @@ namespace Ryujinx.Graphics.Gal.Shader
             return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
         }
 
+        public static void Xmad_CR(ShaderIrBlock Block, long OpCode)
+        {
+            EmitXmad(Block, OpCode, ShaderOper.CR);
+        }
+
+        public static void Xmad_I(ShaderIrBlock Block, long OpCode)
+        {
+            EmitXmad(Block, OpCode, ShaderOper.Imm);
+        }
+
+        public static void Xmad_RC(ShaderIrBlock Block, long OpCode)
+        {
+            EmitXmad(Block, OpCode, ShaderOper.RC);
+        }
+
+        public static void Xmad_RR(ShaderIrBlock Block, long OpCode)
+        {
+            EmitXmad(Block, OpCode, ShaderOper.RR);
+        }
+
         private static void EmitAluBinary(
             ShaderIrBlock Block,
             long          OpCode,
@@ -411,6 +446,16 @@ namespace Ryujinx.Graphics.Gal.Shader
         }
 
         private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            EmitMnmx(Block, OpCode, true, Oper);
+        }
+
+        private static void EmitImnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            EmitMnmx(Block, OpCode, false, Oper);
+        }
+
+        private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
         {
             bool NegB = ((OpCode >> 45) & 1) != 0;
             bool AbsA = ((OpCode >> 46) & 1) != 0;
@@ -419,30 +464,48 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
 
-            OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+            if (IsFloat)
+            {
+                OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+            }
+            else
+            {
+                OperA = GetAluIabsIneg(OperA, AbsA, NegA);
+            }
 
             switch (Oper)
             {
                 case ShaderOper.CR:   OperB = GetOperCbuf34   (OpCode); break;
+                case ShaderOper.Imm:  OperB = GetOperImm19_20 (OpCode); break;
                 case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;
                 case ShaderOper.RR:   OperB = GetOperGpr20    (OpCode); break;
 
                 default: throw new ArgumentException(nameof(Oper));
             }
 
-            OperB = GetAluFabsFneg(OperB, AbsB, NegB);
+            if (IsFloat)
+            {
+                OperB = GetAluFabsFneg(OperB, AbsB, NegB);
+            }
+            else
+            {
+                OperB = GetAluIabsIneg(OperB, AbsB, NegB);
+            }
 
             ShaderIrOperPred Pred = GetOperPred39(OpCode);
 
             ShaderIrOp Op;
 
+            ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
+            ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;
+
             if (Pred.IsConst)
             {
                 bool IsMax = ((OpCode >> 42) & 1) != 0;
 
                 Op = new ShaderIrOp(IsMax
-                    ? ShaderIrInst.Fmax
-                    : ShaderIrInst.Fmin, OperA, OperB);
+                    ? MaxInst
+                    : MinInst, OperA, OperB);
 
                 Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
             }
@@ -450,8 +513,8 @@ namespace Ryujinx.Graphics.Gal.Shader
             {
                 ShaderIrNode PredN = GetOperPred39N(OpCode);
 
-                ShaderIrOp OpMax = new ShaderIrOp(ShaderIrInst.Fmax, OperA, OperB);
-                ShaderIrOp OpMin = new ShaderIrOp(ShaderIrInst.Fmin, OperA, OperB);
+                ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB);
+                ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB);
 
                 ShaderIrAsg AsgMax = new ShaderIrAsg(GetOperGpr0(OpCode), OpMax);
                 ShaderIrAsg AsgMin = new ShaderIrAsg(GetOperGpr0(OpCode), OpMin);
@@ -646,5 +709,94 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
         }
+
+        private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            //TODO: Confirm SignAB/C, it is just a guess.
+            //TODO: Implement Mode 3 (CSFU), what it does?
+            bool SignAB = ((OpCode >> 48) & 1) != 0;
+            bool SignC  = ((OpCode >> 49) & 1) != 0;
+            bool HighB  = ((OpCode >> 52) & 1) != 0;
+            bool HighA  = ((OpCode >> 53) & 1) != 0;
+
+            int Mode = (int)(OpCode >> 50) & 7;
+
+            ShaderIrNode OperA = GetOperGpr8(OpCode), OperB, OperC;
+
+            ShaderIrOperImm Imm16  = new ShaderIrOperImm(16);
+            ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);
+
+            ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
+            ShaderIrInst ShiftC  = SignC  ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
+
+            if (HighA)
+            {
+                OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
+            }
+
+            switch (Oper)
+            {
+                case ShaderOper.CR:  OperB = GetOperCbuf34  (OpCode); break;
+                case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+                case ShaderOper.RC:  OperB = GetOperGpr39   (OpCode); break;
+                case ShaderOper.RR:  OperB = GetOperGpr20   (OpCode); break;
+
+                default: throw new ArgumentException(nameof(Oper));
+            }
+
+            bool ProductShiftLeft = false, Merge = false;
+
+            if (Oper == ShaderOper.RC)
+            {
+                OperC = GetOperCbuf34(OpCode);
+            }
+            else
+            {
+                OperC = GetOperGpr39(OpCode);
+
+                ProductShiftLeft = ((OpCode >> 36) & 1) != 0;
+                Merge            = ((OpCode >> 37) & 1) != 0;
+            }
+
+            switch (Mode)
+            {
+                //CLO.
+                case 1: OperC = ExtendTo32(OperC, SignC, 16); break;
+
+                //CHI.
+                case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
+            }
+
+            ShaderIrNode OperBH = OperB;
+
+            if (HighB)
+            {
+                OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
+            }
+
+            ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);
+
+            if (ProductShiftLeft)
+            {
+                MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
+            }
+
+            ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
+
+            if (Merge)
+            {
+                AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
+                OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
+                AddOp = new ShaderIrOp(ShaderIrInst.Or,  AddOp, OperB);
+            }
+
+            if (Mode == 4)
+            {
+                OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
+                AddOp = new ShaderIrOp(ShaderIrInst.Or,  AddOp, OperB);
+            }
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), AddOp), OpCode));
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
index 6f48d1a8cd..89949d62ee 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
@@ -15,11 +15,11 @@ namespace Ryujinx.Graphics.Gal.Shader
                 throw new NotImplementedException();
             }
 
-            long Target = ((int)(OpCode >> 20) << 8) >> 8;
+            int Target = ((int)(OpCode >> 20) << 8) >> 8;
 
-            Target += Block.Position + 8;
+            ShaderIrOperImm Imm = new ShaderIrOperImm(Target);
 
-            Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Block.GetLabel(Target)), OpCode));
+            Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm), OpCode));
         }
 
         public static void Exit(ShaderIrBlock Block, long OpCode)
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
index 024fa36489..85522ff950 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
@@ -1,19 +1,133 @@
+using System.Collections.Generic;
+
 namespace Ryujinx.Graphics.Gal.Shader
 {
     static class ShaderDecoder
     {
         private const bool AddDbgComments = true;
 
-        public static ShaderIrBlock DecodeBasicBlock(IGalMemory Memory, long Position)
+        public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
         {
-            ShaderIrBlock Block = new ShaderIrBlock();
+            Dictionary<long, ShaderIrBlock> Visited    = new Dictionary<long, ShaderIrBlock>();
+            Dictionary<long, ShaderIrBlock> VisitedEnd = new Dictionary<long, ShaderIrBlock>();
 
-            while (true)
+            Queue<ShaderIrBlock> Blocks = new Queue<ShaderIrBlock>();
+
+            ShaderIrBlock Enqueue(long Position, ShaderIrBlock Source = null)
             {
-                Block.Position = Position;
+                if (!Visited.TryGetValue(Position, out ShaderIrBlock Output))
+                {
+                    Output = new ShaderIrBlock(Position);
 
-                Block.MarkLabel(Position);
+                    Blocks.Enqueue(Output);
 
+                    Visited.Add(Position, Output);
+                }
+
+                if (Source != null)
+                {
+                    Output.Sources.Add(Source);
+                }
+
+                return Output;
+            }
+
+            ShaderIrBlock Entry = Enqueue(Start);
+
+            while (Blocks.Count > 0)
+            {
+                ShaderIrBlock Current = Blocks.Dequeue();
+
+                FillBlock(Memory, Current);
+
+                //Set child blocks. "Branch" is the block the branch instruction
+                //points to (when taken), "Next" is the block at the next address,
+                //executed when the branch is not taken. For Unconditional Branches
+                //or end of shader, Next is null.
+                if (Current.Nodes.Count > 0)
+                {
+                    ShaderIrNode LastNode = Current.GetLastNode();
+
+                    ShaderIrOp Op = GetInnermostOp(LastNode);
+
+                    if (Op?.Inst == ShaderIrInst.Bra)
+                    {
+                        int Offset = ((ShaderIrOperImm)Op.OperandA).Value;
+
+                        long Target = Current.EndPosition + Offset;
+
+                        Current.Branch = Enqueue(Target, Current);
+                    }
+
+                    if (NodeHasNext(LastNode))
+                    {
+                        Current.Next = Enqueue(Current.EndPosition);
+                    }
+                }
+
+                //If we have on the graph two blocks with the same end position,
+                //then we need to split the bigger block and have two small blocks,
+                //the end position of the bigger "Current" block should then be == to
+                //the position of the "Smaller" block.
+                while (VisitedEnd.TryGetValue(Current.EndPosition, out ShaderIrBlock Smaller))
+                {
+                    if (Current.Position > Smaller.Position)
+                    {
+                        ShaderIrBlock Temp = Smaller;
+
+                        Smaller = Current;
+                        Current = Temp;
+                    }
+
+                    Current.EndPosition = Smaller.Position;
+                    Current.Next        = Smaller;
+                    Current.Branch      = null;
+
+                    Current.Nodes.RemoveRange(
+                        Current.Nodes.Count - Smaller.Nodes.Count,
+                        Smaller.Nodes.Count);
+
+                    VisitedEnd[Smaller.EndPosition] = Smaller;
+                }
+
+                VisitedEnd.Add(Current.EndPosition, Current);
+            }
+
+            //Make and sort Graph blocks array by position.
+            ShaderIrBlock[] Graph = new ShaderIrBlock[Visited.Count];
+
+            while (Visited.Count > 0)
+            {
+                ulong FirstPos = ulong.MaxValue;
+
+                foreach (ShaderIrBlock Block in Visited.Values)
+                {
+                    if (FirstPos > (ulong)Block.Position)
+                        FirstPos = (ulong)Block.Position;
+                }
+
+                ShaderIrBlock Current = Visited[(long)FirstPos];
+
+                do
+                {
+                    Graph[Graph.Length - Visited.Count] = Current;
+
+                    Visited.Remove(Current.Position);
+
+                    Current = Current.Next;
+                }
+                while (Current != null);
+            }
+
+            return Graph;
+        }
+
+        private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block)
+        {
+            long Position = Block.Position;
+
+            do
+            {
                 //Ignore scheduling instructions, which are written every 32 bytes.
                 if ((Position & 0x1f) == 0)
                 {
@@ -33,9 +147,20 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 if (AddDbgComments)
                 {
-                    string DbgOpCode = $"0x{Position:x16}: 0x{OpCode:x16} ";
+                    string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
 
-                    Block.AddNode(new ShaderIrCmnt(DbgOpCode + (Decode?.Method.Name ?? "???")));
+                    DbgOpCode += (Decode?.Method.Name ?? "???");
+
+                    if (Decode == ShaderDecode.Bra)
+                    {
+                        int Offset = ((int)(OpCode >> 20) << 8) >> 8;
+
+                        long Target = Position + Offset;
+
+                        DbgOpCode += " (0x" + Target.ToString("x16") + ")";
+                    }
+
+                    Block.AddNode(new ShaderIrCmnt(DbgOpCode));
                 }
 
                 if (Decode == null)
@@ -44,19 +169,36 @@ namespace Ryujinx.Graphics.Gal.Shader
                 }
 
                 Decode(Block, OpCode);
-
-                if (Block.GetLastNode() is ShaderIrOp Op && Op.Inst == ShaderIrInst.Exit)
-                {
-                    break;
-                }
             }
+            while (!IsFlowChange(Block.GetLastNode()));
 
-            return Block;
+            Block.EndPosition = Position;
         }
 
-        private static bool IsFlowChange(ShaderIrInst Inst)
+        private static bool IsFlowChange(ShaderIrNode Node)
         {
-            return Inst == ShaderIrInst.Exit;
+            return !NodeHasNext(GetInnermostOp(Node));
+        }
+
+        private static ShaderIrOp GetInnermostOp(ShaderIrNode Node)
+        {
+            if (Node is ShaderIrCond Cond)
+            {
+                Node = Cond.Child;
+            }
+
+            return Node is ShaderIrOp Op ? Op : null;
+        }
+
+        private static bool NodeHasNext(ShaderIrNode Node)
+        {
+            if (!(Node is ShaderIrOp Op))
+            {
+                return true;
+            }
+
+            return Op.Inst != ShaderIrInst.Exit &&
+                   Op.Inst != ShaderIrInst.Bra;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
index 31d7216964..50e563b846 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
@@ -4,17 +4,23 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     class ShaderIrBlock
     {
-        private List<ShaderIrNode> Nodes;
+        public long Position    { get; set; }
+        public long EndPosition { get; set; }
 
-        private Dictionary<long, ShaderIrLabel> LabelsToInsert;
+        public ShaderIrBlock Next   { get; set; }
+        public ShaderIrBlock Branch { get; set; }
 
-        public long Position;
+        public List<ShaderIrBlock> Sources { get; private set; }
 
-        public ShaderIrBlock()
+        public List<ShaderIrNode> Nodes { get; private set; }
+
+        public ShaderIrBlock(long Position)
         {
-            Nodes = new List<ShaderIrNode>();
+            this.Position = Position;
 
-            LabelsToInsert = new Dictionary<long, ShaderIrLabel>();
+            Sources = new List<ShaderIrBlock>();
+
+            Nodes = new List<ShaderIrNode>();
         }
 
         public void AddNode(ShaderIrNode Node)
@@ -22,28 +28,6 @@ namespace Ryujinx.Graphics.Gal.Shader
             Nodes.Add(Node);
         }
 
-        public ShaderIrLabel GetLabel(long Position)
-        {
-            if (LabelsToInsert.TryGetValue(Position, out ShaderIrLabel Label))
-            {
-                return Label;
-            }
-
-            Label = new ShaderIrLabel();
-
-            LabelsToInsert.Add(Position, Label);
-
-            return Label;
-        }
-
-        public void MarkLabel(long Position)
-        {
-            if (LabelsToInsert.TryGetValue(Position, out ShaderIrLabel Label))
-            {
-                Nodes.Add(Label);
-            }
-        }
-
         public ShaderIrNode[] GetNodes()
         {
             return Nodes.ToArray();
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index af2ccc3b3b..2de50a4a78 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -65,6 +65,8 @@ namespace Ryujinx.Graphics.Gal.Shader
         Cne,
         Lsl,
         Lsr,
+        Max,
+        Min,
         Mul,
         Neg,
         Not,
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
deleted file mode 100644
index f5b3585af8..0000000000
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrLabel : ShaderIrNode { }
-}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index acfcc147c0..51197fd482 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -63,6 +63,9 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("0100110011100x", ShaderDecode.I2i_C);
             Set("0011100x11100x", ShaderDecode.I2i_I);
             Set("0101110011100x", ShaderDecode.I2i_R);
+            Set("0100110000100x", ShaderDecode.Imnmx_C);
+            Set("0011100x00100x", ShaderDecode.Imnmx_I);
+            Set("0101110000100x", ShaderDecode.Imnmx_R);
             Set("11100000xxxxxx", ShaderDecode.Ipa);
             Set("0100110000011x", ShaderDecode.Iscadd_C);
             Set("0011100x00011x", ShaderDecode.Iscadd_I);
@@ -89,6 +92,10 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("1101111101001x", ShaderDecode.Texq);
             Set("1101100xxxxxxx", ShaderDecode.Texs);
             Set("1101101xxxxxxx", ShaderDecode.Tlds);
+            Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
+            Set("0011011x00xxxx", ShaderDecode.Xmad_I);
+            Set("010100010xxxxx", ShaderDecode.Xmad_RC);
+            Set("0101101100xxxx", ShaderDecode.Xmad_RR);
 #endregion
         }