[hlsl] Add vector element storage store support

This CL adds support for storing to vector elements in the
DecomposeStorageAccess transform.

Bug: 42251045
Change-Id: Id81a5b4fb672adbc6ae123c32f69dcdb85cc17e2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/197777
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/hlsl/writer/access_test.cc b/src/tint/lang/hlsl/writer/access_test.cc
index edbb41a..784d0f8 100644
--- a/src/tint/lang/hlsl/writer/access_test.cc
+++ b/src/tint/lang/hlsl/writer/access_test.cc
@@ -1332,14 +1332,15 @@
 )");
 }
 
-TEST_F(HlslWriterTest, DISABLED_AccessStoreVectorElement) {
+TEST_F(HlslWriterTest, AccessStoreVectorElement) {
     auto* var = b.Var<storage, vec3<f32>, core::Access::kReadWrite>("v");
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
-        b.Store(b.Access(ty.ptr<storage, f32, core::Access::kReadWrite>(), var, 1_u), 2_f);
+        b.StoreVectorElement(b.Access(ty.ptr<storage, vec3<f32>, core::Access::kReadWrite>(), var),
+                             1_u, 2_f);
         b.Return(func);
     });
 
@@ -1347,8 +1348,9 @@
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
 void foo() {
-  v.Store(4u, 2.0f);
+  v.Store(4u, asuint(2.0f));
 }
+
 )");
 }
 
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc b/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
index c2e8261..e23e834 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
@@ -116,7 +116,7 @@
                     [&](core::ir::StoreVectorElement* s) { StoreVectorElement(s, var, var_ty); },
                     [&](core::ir::Store* s) {
                         OffsetData offset{};
-                        Store(s, var, offset);
+                        Store(s, var, s->From(), offset);
                     },
                     [&](core::ir::Load* l) {
                         OffsetData offset{};
@@ -211,8 +211,8 @@
             return MakeScalarOrVectorStore(var, from, offset);
         }
 
-        // TODO(dsinclair): This currently only handles scalars and entire vectors. Add vector
-        // elements, matrices, structs ...
+        // TODO(dsinclair): This currently only handles scalars vectors. Add arrays, matrices,
+        // structs ...
 
         TINT_UNREACHABLE();
     }
@@ -513,12 +513,15 @@
                     Load(ld, var, *offset);
                 },
 
-                [&](core::ir::StoreVectorElement*) {
-                    // TODO(dsinclair): Handle store vector elements
+                [&](core::ir::StoreVectorElement* sve) {
+                    a->Result(0)->RemoveUsage(usage);
+
+                    b.InsertBefore(sve, [&] {
+                        UpdateOffsetData(sve->Index(), obj->DeepestElement()->Size(), offset);
+                    });
+                    Store(sve, var, sve->Value(), *offset);
                 },
-                [&](core::ir::Store* store) {  //
-                    Store(store, var, *offset);
-                },
+                [&](core::ir::Store* store) { Store(store, var, store->From(), *offset); },
                 [&](core::ir::CoreBuiltinCall* call) {
                     // Array length calls require the access
                     TINT_ASSERT(call->Func() == core::BuiltinFn::kArrayLength);
@@ -535,12 +538,15 @@
         a->Destroy();
     }
 
-    void Store(core::ir::Store* store, core::ir::Var* var, OffsetData& offset) {
-        b.InsertBefore(store, [&] {
+    void Store(core::ir::Instruction* inst,
+               core::ir::Var* var,
+               core::ir::Value* from,
+               OffsetData& offset) {
+        b.InsertBefore(inst, [&] {
             auto* off = OffsetToValue(offset);
-            MakeStore(var, store->From(), off);
+            MakeStore(var, from, off);
         });
-        store->Destroy();
+        inst->Destroy();
     }
 
     void Load(core::ir::Instruction* inst, core::ir::Var* var, OffsetData& offset) {
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc b/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
index ee7653c..134afca 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
@@ -2506,26 +2506,27 @@
     EXPECT_EQ(expect, str());
 }
 
-TEST_F(HlslWriterDecomposeStorageAccessTest, DISABLED_StoreVectorElement) {
+TEST_F(HlslWriterDecomposeStorageAccessTest, StoreVectorElement) {
     auto* var = b.Var<storage, vec3<f32>, core::Access::kReadWrite>("v");
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
-        b.Store(b.Access(ty.ptr<storage, f32, core::Access::kReadWrite>(), var, 1_u), 2_f);
+        b.StoreVectorElement(b.Access(ty.ptr<storage, vec3<f32>, core::Access::kReadWrite>(), var),
+                             1_u, 2_f);
         b.Return(func);
     });
 
     auto* src = R"(
 $B1: {  # root
-  %v:ptr<storage, mat4x4<f32>, read_write> = var @binding_point(0, 0)
+  %v:ptr<storage, vec3<f32>, read_write> = var @binding_point(0, 0)
 }
 
 %foo = @fragment func():void {
   $B2: {
-    %3:ptr<storage, vec4<f32>, read_write> = access %v, 1u
-    store_vector_element %3, 2u, 5.0f
+    %3:ptr<storage, vec3<f32>, read_write> = access %v
+    store_vector_element %3, 1u, 2.0f
     ret
   }
 }
@@ -2533,6 +2534,17 @@
     ASSERT_EQ(src, str());
 
     auto* expect = R"(
+$B1: {  # root
+  %v:hlsl.byte_address_buffer<read_write> = var @binding_point(0, 0)
+}
+
+%foo = @fragment func():void {
+  $B2: {
+    %3:u32 = bitcast 2.0f
+    %4:void = %v.Store 4u, %3
+    ret
+  }
+}
 )";
     Run(DecomposeStorageAccess);
     EXPECT_EQ(expect, str());