[spirv-reader][ir] Convert load/store usages of atomics

With the atomic types changed, we need to update any load/store of the
original SPIR-V value to the atomic equivalents.

Bug: 404501988
Change-Id: Idc48fa529bbf593a5a5ffda0693fe0ba355712e3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/236954
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/reader/lower/atomics.cc b/src/tint/lang/spirv/reader/lower/atomics.cc
index 23fe305..8b25e2b 100644
--- a/src/tint/lang/spirv/reader/lower/atomics.cc
+++ b/src/tint/lang/spirv/reader/lower/atomics.cc
@@ -58,8 +58,14 @@
     /// The `ir::Value`s to be converted to atomics
     Vector<core::ir::Value*, 8> values_to_convert_{};
 
+    /// The `ir::Values`s which have had their types changed, they then need to have their
+    /// loads/stores updated to match. This maps to the root FunctionParam or Var for each atomic.
+    Hashset<core::ir::Value*, 8> values_to_fix_usages_{};
+
     /// The `ir::Value`s which have been converted
     Hashset<core::ir::Value*, 8> converted_{};
+    /// The `ir::Value`s which have had their usages updated
+    Hashset<core::ir::Value*, 8> usages_updated_{};
 
     struct ForkedStruct {
         const core::type::Struct* src_struct = nullptr;
@@ -264,14 +270,19 @@
                 auto* atomic_ty = AtomicTypeFor(val, orig_ty);
                 res->SetType(atomic_ty);
 
-                tint::Switch(            //
-                    res->Instruction(),  //
+                tint::Switch(
+                    res->Instruction(),
                     [&](core::ir::Access* a) {
                         CheckForStructForking(a);
                         values_to_convert_.Push(a->Object());
-                    },                                                               //
-                    [&](core::ir::Let* l) { values_to_convert_.Push(l->Value()); },  //
-                    [&](core::ir::Var*) {},                                          //
+                    },
+                    [&](core::ir::Let* l) { values_to_convert_.Push(l->Value()); },
+                    [&](core::ir::Var* v) {
+                        auto* var_res = v->Result();
+                        if (usages_updated_.Add(var_res)) {
+                            ConvertUsages(var_res);
+                        }
+                    },
                     TINT_ICE_ON_NO_MATCH);
             },
             [&](core::ir::FunctionParam* param) {
@@ -279,6 +290,10 @@
                 auto* atomic_ty = AtomicTypeFor(val, orig_ty);
                 param->SetType(atomic_ty);
 
+                if (usages_updated_.Add(param)) {
+                    ConvertUsages(param);
+                }
+
                 for (auto& usage : param->Function()->UsagesUnsorted()) {
                     if (usage->instruction->Is<core::ir::Return>()) {
                         continue;
@@ -292,6 +307,28 @@
             TINT_ICE_ON_NO_MATCH);
     }
 
+    void ConvertUsages(core::ir::Value* val) {
+        val->ForEachUseUnsorted([&](const core::ir::Usage& usage) {
+            auto* inst = usage.instruction;
+
+            tint::Switch(  //
+                inst,
+                [&](core::ir::Load* ld) {
+                    b.InsertBefore(ld, [&] {
+                        b.CallWithResult(ld->DetachResult(), core::BuiltinFn::kAtomicLoad,
+                                         ld->From());
+                    });
+                    ld->Destroy();
+                },
+                [&](core::ir::Store* st) {
+                    b.InsertBefore(st, [&] {
+                        b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, st->To(), st->From());
+                    });
+                    st->Destroy();
+                });
+        });
+    }
+
     void CheckForStructForking(core::ir::Access* access) {
         auto* cur_ty = access->Object()->Type()->UnwrapPtr();
         for (auto* idx : access->Indices()) {
diff --git a/src/tint/lang/spirv/reader/lower/atomics_test.cc b/src/tint/lang/spirv/reader/lower/atomics_test.cc
index aef1ce2..3a163d4 100644
--- a/src/tint/lang/spirv/reader/lower/atomics_test.cc
+++ b/src/tint/lang/spirv/reader/lower/atomics_test.cc
@@ -1973,7 +1973,7 @@
     ASSERT_EQ(expect, str());
 }
 
-TEST_F(SpirvReader_AtomicsTest, DISABLED_ReplaceAssignsAndDecls_Scalar) {
+TEST_F(SpirvReader_AtomicsTest, ReplaceAssignsAndDecls_Scalar) {
     auto* f = b.ComputeFunction("main");
 
     core::ir::Var* wg = nullptr;
@@ -2013,7 +2013,22 @@
     Run(Atomics);
 
     auto* expect = R"(
-UNIMPLEMENTED
+$B1: {  # root
+  %wg:ptr<workgroup, atomic<u32>, read_write> = var undef
+}
+
+%main = @compute @workgroup_size(1u, 1u, 1u) func():void {
+  $B2: {
+    %b:ptr<function, u32, read_write> = var undef
+    %4:u32 = atomicAdd %wg, 0u
+    %5:void = atomicStore %wg, 0u
+    %6:u32 = atomicLoad %wg
+    %7:u32 = let %6
+    %8:u32 = atomicLoad %wg
+    store %b, %8
+    ret
+  }
+}
 )";
     ASSERT_EQ(expect, str());
 }