From 0a54291c9c750d89feacef0644959326b9612b64 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Thu, 20 May 2021 15:58:39 -0300
Subject: glasm: Fix potential aliasing bug on cube array samples

---
 .../backend/glasm/emit_glasm_image.cpp             | 71 ++++++++++++----------
 1 file changed, 40 insertions(+), 31 deletions(-)

(limited to 'src/shader_recompiler/backend/glasm/emit_glasm_image.cpp')

diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index ed0b65e162..385ca51ac5 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -268,9 +268,16 @@ void EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Valu
 }
 
 void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
-                                    const IR::Value& coord, ScalarF32 dref, Register bias_lc,
-                                    const IR::Value& offset) {
+                                    const IR::Value& coord, const IR::Value& dref,
+                                    const IR::Value& bias_lc, const IR::Value& offset) {
+    // Allocate early to avoid aliases
     const auto info{inst.Flags<IR::TextureInstInfo>()};
+    ScopedRegister staging;
+    if (info.type == TextureType::ColorArrayCube) {
+        staging = ScopedRegister{ctx.reg_alloc};
+    }
+    const ScalarF32 dref_val{ctx.reg_alloc.Consume(dref)};
+    const Register bias_lc_vec{ctx.reg_alloc.Consume(bias_lc)};
     const auto sparse_inst{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
     const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
     const std::string_view type{TextureType(info)};
@@ -287,14 +294,14 @@ void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
                 ctx.Add("MOV.F {}.z,{};"
                         "MOV.F {}.w,{}.x;"
                         "TXB.F.LODCLAMP{} {},{},{}.y,{},{}{};",
-                        coord_vec, dref, coord_vec, bias_lc, sparse_mod, ret, coord_vec, bias_lc,
-                        texture, type, offset_vec);
+                        coord_vec, dref_val, coord_vec, bias_lc_vec, sparse_mod, ret, coord_vec,
+                        bias_lc_vec, texture, type, offset_vec);
                 break;
             case TextureType::ColorArray2D:
             case TextureType::ColorCube:
                 ctx.Add("MOV.F {}.w,{};"
                         "TXB.F.LODCLAMP{} {},{},{},{},{}{};",
-                        coord_vec, dref, sparse_mod, ret, coord_vec, bias_lc, texture, type,
+                        coord_vec, dref_val, sparse_mod, ret, coord_vec, bias_lc_vec, texture, type,
                         offset_vec);
                 break;
             default:
@@ -309,25 +316,23 @@ void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
                 ctx.Add("MOV.F {}.z,{};"
                         "MOV.F {}.w,{}.x;"
                         "TXB.F{} {},{},{},{}{};",
-                        coord_vec, dref, coord_vec, bias_lc, sparse_mod, ret, coord_vec, texture,
-                        type, offset_vec);
+                        coord_vec, dref_val, coord_vec, bias_lc_vec, sparse_mod, ret, coord_vec,
+                        texture, type, offset_vec);
                 break;
             case TextureType::ColorArray2D:
             case TextureType::ColorCube:
                 ctx.Add("MOV.F {}.w,{};"
                         "TXB.F{} {},{},{},{},{}{};",
-                        coord_vec, dref, sparse_mod, ret, coord_vec, bias_lc, texture, type,
+                        coord_vec, dref_val, sparse_mod, ret, coord_vec, bias_lc_vec, texture, type,
                         offset_vec);
                 break;
-            case TextureType::ColorArrayCube: {
-                const ScopedRegister pair{ctx.reg_alloc};
+            case TextureType::ColorArrayCube:
                 ctx.Add("MOV.F {}.x,{};"
                         "MOV.F {}.y,{}.x;"
                         "TXB.F{} {},{},{},{},{}{};",
-                        pair.reg, dref, pair.reg, bias_lc, sparse_mod, ret, coord_vec, pair.reg,
-                        texture, type, offset_vec);
+                        staging.reg, dref_val, staging.reg, bias_lc_vec, sparse_mod, ret, coord_vec,
+                        staging.reg, texture, type, offset_vec);
                 break;
-            }
             default:
                 throw NotImplementedException("Invalid type {}", info.type.Value());
             }
@@ -340,15 +345,14 @@ void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
                 const char dref_swizzle{w_swizzle ? 'w' : 'z'};
                 ctx.Add("MOV.F {}.{},{};"
                         "TEX.F.LODCLAMP{} {},{},{},{},{}{};",
-                        coord_vec, dref_swizzle, dref, sparse_mod, ret, coord_vec, bias_lc, texture,
-                        type, offset_vec);
+                        coord_vec, dref_swizzle, dref_val, sparse_mod, ret, coord_vec, bias_lc_vec,
+                        texture, type, offset_vec);
             } else {
-                const ScopedRegister pair{ctx.reg_alloc};
                 ctx.Add("MOV.F {}.x,{};"
                         "MOV.F {}.y,{};"
                         "TEX.F.LODCLAMP{} {},{},{},{},{}{};",
-                        pair.reg, dref, pair.reg, bias_lc, sparse_mod, ret, coord_vec, pair.reg,
-                        texture, type, offset_vec);
+                        staging.reg, dref_val, staging.reg, bias_lc_vec, sparse_mod, ret, coord_vec,
+                        staging.reg, texture, type, offset_vec);
             }
         } else {
             if (info.type != TextureType::ColorArrayCube) {
@@ -357,11 +361,10 @@ void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
                 const char dref_swizzle{w_swizzle ? 'w' : 'z'};
                 ctx.Add("MOV.F {}.{},{};"
                         "TEX.F{} {},{},{},{}{};",
-                        coord_vec, dref_swizzle, dref, sparse_mod, ret, coord_vec, texture, type,
-                        offset_vec);
+                        coord_vec, dref_swizzle, dref_val, sparse_mod, ret, coord_vec, texture,
+                        type, offset_vec);
             } else {
-                const ScopedRegister pair{ctx.reg_alloc};
-                ctx.Add("TEX.F{} {},{},{},{},{}{};", sparse_mod, ret, coord_vec, dref, texture,
+                ctx.Add("TEX.F{} {},{},{},{},{}{};", sparse_mod, ret, coord_vec, dref_val, texture,
                         type, offset_vec);
             }
         }
@@ -370,9 +373,16 @@ void EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
 }
 
 void EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
-                                    const IR::Value& coord, ScalarF32 dref, ScalarF32 lod,
-                                    const IR::Value& offset) {
+                                    const IR::Value& coord, const IR::Value& dref,
+                                    const IR::Value& lod, const IR::Value& offset) {
+    // Allocate early to avoid aliases
     const auto info{inst.Flags<IR::TextureInstInfo>()};
+    ScopedRegister staging;
+    if (info.type == TextureType::ColorArrayCube) {
+        staging = ScopedRegister{ctx.reg_alloc};
+    }
+    const ScalarF32 dref_val{ctx.reg_alloc.Consume(dref)};
+    const ScalarF32 lod_val{ctx.reg_alloc.Consume(lod)};
     const auto sparse_inst{inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp)};
     const std::string_view sparse_mod{sparse_inst ? ".SPARSE" : ""};
     const std::string_view type{TextureType(info)};
@@ -387,24 +397,23 @@ void EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::
         ctx.Add("MOV.F {}.z,{};"
                 "MOV.F {}.w,{};"
                 "TXL.F{} {},{},{},{}{};",
-                coord_vec, dref, coord_vec, lod, sparse_mod, ret, coord_vec, texture, type,
+                coord_vec, dref_val, coord_vec, lod_val, sparse_mod, ret, coord_vec, texture, type,
                 offset_vec);
         break;
     case TextureType::ColorArray2D:
     case TextureType::ColorCube:
         ctx.Add("MOV.F {}.w,{};"
                 "TXL.F{} {},{},{},{},{}{};",
-                coord_vec, dref, sparse_mod, ret, coord_vec, lod, texture, type, offset_vec);
+                coord_vec, dref_val, sparse_mod, ret, coord_vec, lod_val, texture, type,
+                offset_vec);
         break;
-    case TextureType::ColorArrayCube: {
-        const ScopedRegister pair{ctx.reg_alloc};
+    case TextureType::ColorArrayCube:
         ctx.Add("MOV.F {}.x,{};"
                 "MOV.F {}.y,{};"
                 "TXL.F{} {},{},{},{},{}{};",
-                pair.reg, dref, pair.reg, lod, sparse_mod, ret, coord_vec, pair.reg, texture, type,
-                offset_vec);
+                staging.reg, dref_val, staging.reg, lod_val, sparse_mod, ret, coord_vec,
+                staging.reg, texture, type, offset_vec);
         break;
-    }
     default:
         throw NotImplementedException("Invalid type {}", info.type.Value());
     }
-- 
cgit v1.2.3-70-g09d2