From 4523a73f75528d57bc7bc6d78024a6737a012a86 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Mon, 11 Jul 2022 19:36:58 -0300
Subject: [PATCH] Propagate Shader phi nodes with the same source value from
 all blocks (#3457)

* Propagate Shader phi nodes with the same source value from all incoming blocks

* Shader cache version bump
---
 .../Shader/DiskCache/DiskCacheHostStorage.cs  |  2 +-
 .../Translation/Optimizations/Optimizer.cs    | 53 +++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 37b25793ff..c332e2df64 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
         private const ushort FileFormatVersionMajor = 1;
         private const ushort FileFormatVersionMinor = 1;
         private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
-        private const uint CodeGenVersion = 3069;
+        private const uint CodeGenVersion = 3457;
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
diff --git a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
index 078f3bb9eb..47963eacc5 100644
--- a/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs
@@ -45,6 +45,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
 
                         if (!(node.Value is Operation operation) || isUnused)
                         {
+                            if (node.Value is PhiNode phi && !isUnused)
+                            {
+                                isUnused = PropagatePhi(phi);
+                            }
+
                             if (isUnused)
                             {
                                 RemoveNode(block, node);
@@ -101,6 +106,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
         {
             // Propagate copy source operand to all uses of
             // the destination operand.
+
             Operand dest = copyOp.Dest;
             Operand src  = copyOp.GetSource(0);
 
@@ -118,6 +124,53 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
             }
         }
 
+        private static bool PropagatePhi(PhiNode phi)
+        {
+            // If all phi sources are the same, we can propagate it and remove the phi.
+
+            Operand firstSrc = phi.GetSource(0);
+
+            for (int index = 1; index < phi.SourcesCount; index++)
+            {
+                if (!IsSameOperand(firstSrc, phi.GetSource(index)))
+                {
+                    return false;
+                }
+            }
+
+            // All sources are equal, we can propagate the value.
+
+            Operand dest = phi.Dest;
+
+            INode[] uses = dest.UseOps.ToArray();
+
+            foreach (INode useNode in uses)
+            {
+                for (int index = 0; index < useNode.SourcesCount; index++)
+                {
+                    if (useNode.GetSource(index) == dest)
+                    {
+                        useNode.SetSource(index, firstSrc);
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        private static bool IsSameOperand(Operand x, Operand y)
+        {
+            if (x.Type != y.Type || x.Value != y.Value)
+            {
+                return false;
+            }
+
+            return x.Type == OperandType.Attribute ||
+                   x.Type == OperandType.AttributePerPatch ||
+                   x.Type == OperandType.Constant ||
+                   x.Type == OperandType.ConstantBuffer;
+        }
+
         private static bool PropagatePack(Operation packOp)
         {
             // Propagate pack source operands to uses by unpack