[tint][ir] Serialize Swizzle instruction

Change-Id: I24066ea619a3f0fb9c72e6b6046ae34dc81b9c5d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/164880
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index 8ffd626..6d235882 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -196,6 +196,9 @@
             case pb::Instruction::KindCase::kStoreVectorElement:
                 inst_out = CreateInstructionStoreVectorElement(inst_in.store_vector_element());
                 break;
+            case pb::Instruction::KindCase::kSwizzle:
+                inst_out = CreateInstructionSwizzle(inst_in.swizzle());
+                break;
             case pb::Instruction::KindCase::kUnary:
                 inst_out = CreateInstructionUnary(inst_in.unary());
                 break;
@@ -270,6 +273,16 @@
         return mod_out_.instructions.Create<ir::StoreVectorElement>();
     }
 
+    ir::Swizzle* CreateInstructionSwizzle(const pb::InstructionSwizzle& swizzle_in) {
+        auto* swizzle_out = mod_out_.instructions.Create<ir::Swizzle>();
+        Vector<uint32_t, 4> indices;
+        for (auto idx : swizzle_in.indices()) {
+            indices.Push(idx);
+        }
+        swizzle_out->SetIndices(indices);
+        return swizzle_out;
+    }
+
     ir::Unary* CreateInstructionUnary(const pb::InstructionUnary& unary_in) {
         auto* unary_out = mod_out_.instructions.Create<ir::Unary>();
         unary_out->SetOp(UnaryOp(unary_in.op()));
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index c2b175f..7846a4a 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -44,6 +44,7 @@
 #include "src/tint/lang/core/ir/return.h"
 #include "src/tint/lang/core/ir/store.h"
 #include "src/tint/lang/core/ir/store_vector_element.h"
+#include "src/tint/lang/core/ir/swizzle.h"
 #include "src/tint/lang/core/ir/unary.h"
 #include "src/tint/lang/core/ir/user_call.h"
 #include "src/tint/lang/core/ir/var.h"
@@ -162,6 +163,7 @@
             [&](const ir::StoreVectorElement* i) {
                 InstructionStoreVectorElement(*inst_out.mutable_store_vector_element(), i);
             },
+            [&](const ir::Swizzle* i) { InstructionSwizzle(*inst_out.mutable_swizzle(), i); },
             [&](const ir::Unary* i) { InstructionUnary(*inst_out.mutable_unary(), i); },
             [&](const ir::UserCall* i) { InstructionUserCall(*inst_out.mutable_user_call(), i); },
             [&](const ir::Var* i) { InstructionVar(*inst_out.mutable_var(), i); },
@@ -198,6 +200,12 @@
     void InstructionStoreVectorElement(pb::InstructionStoreVectorElement&,
                                        const ir::StoreVectorElement*) {}
 
+    void InstructionSwizzle(pb::InstructionSwizzle& swizzle_out, const ir::Swizzle* swizzle_in) {
+        for (auto idx : swizzle_in->Indices()) {
+            swizzle_out.add_indices(idx);
+        }
+    }
+
     void InstructionUnary(pb::InstructionUnary& unary_out, const ir::Unary* unary_in) {
         unary_out.set_op(UnaryOp(unary_in->Op()));
     }
diff --git a/src/tint/lang/core/ir/binary/ir.proto b/src/tint/lang/core/ir/binary/ir.proto
index 67d6caa..3db27a5 100644
--- a/src/tint/lang/core/ir/binary/ir.proto
+++ b/src/tint/lang/core/ir/binary/ir.proto
@@ -194,6 +194,7 @@
         InstructionStore store = 15;
         InstructionLoadVectorElement load_vector_element = 16;
         InstructionStoreVectorElement store_vector_element = 17;
+        InstructionSwizzle swizzle = 18;
     }
 }
 
@@ -233,6 +234,10 @@
 
 message InstructionStoreVectorElement {}
 
+message InstructionSwizzle {
+    repeated uint32 indices = 1;
+}
+
 message BindingPoint {
     uint32 group = 1;
     uint32 binding = 2;
diff --git a/src/tint/lang/core/ir/binary/roundtrip_test.cc b/src/tint/lang/core/ir/binary/roundtrip_test.cc
index 42f199c..57ade4e 100644
--- a/src/tint/lang/core/ir/binary/roundtrip_test.cc
+++ b/src/tint/lang/core/ir/binary/roundtrip_test.cc
@@ -304,5 +304,15 @@
     RUN_TEST();
 }
 
+TEST_F(IRBinaryRoundtripTest, Swizzle) {
+    auto x = b.FunctionParam<vec4<f32>>("x");
+    auto* fn = b.Function("Function", ty.vec3<f32>());
+    fn->SetParams({x});
+    b.Append(fn->Block(), [&] {
+        b.Return(fn, b.Swizzle<vec3<f32>>(x, Vector<uint32_t, 3>{1, 0, 2}));
+    });
+    RUN_TEST();
+}
+
 }  // namespace
 }  // namespace tint::core::ir::binary
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 8a9644d..bdbd507 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -1315,6 +1315,17 @@
     }
 
     /// Creates a new `Swizzle`
+    /// @tparam TYPE the return type
+    /// @param object the object being swizzled
+    /// @param indices the swizzle indices
+    /// @returns the instruction
+    template <typename TYPE, typename OBJ>
+    ir::Swizzle* Swizzle(OBJ&& object, VectorRef<uint32_t> indices) {
+        auto* type = ir.Types().Get<TYPE>();
+        return Swizzle(type, std::forward<OBJ>(object), std::move(indices));
+    }
+
+    /// Creates a new `Swizzle`
     /// @param type the return type
     /// @param object the object being swizzled
     /// @param indices the swizzle indices
diff --git a/src/tint/lang/core/ir/swizzle.cc b/src/tint/lang/core/ir/swizzle.cc
index 1a1e6dc..184ddf6 100644
--- a/src/tint/lang/core/ir/swizzle.cc
+++ b/src/tint/lang/core/ir/swizzle.cc
@@ -37,6 +37,8 @@
 
 namespace tint::core::ir {
 
+Swizzle::Swizzle() = default;
+
 Swizzle::Swizzle(InstructionResult* result, Value* object, VectorRef<uint32_t> indices)
     : indices_(std::move(indices)) {
     TINT_ASSERT(!indices.IsEmpty());
diff --git a/src/tint/lang/core/ir/swizzle.h b/src/tint/lang/core/ir/swizzle.h
index 1e5b0fc..88740d0 100644
--- a/src/tint/lang/core/ir/swizzle.h
+++ b/src/tint/lang/core/ir/swizzle.h
@@ -29,6 +29,7 @@
 #define SRC_TINT_LANG_CORE_IR_SWIZZLE_H_
 
 #include <string>
+#include <utility>
 
 #include "src/tint/lang/core/ir/operand_instruction.h"
 #include "src/tint/utils/rtti/castable.h"
@@ -41,6 +42,9 @@
     /// The offset in Operands() for the object being swizzled
     static constexpr size_t kObjectOperandOffset = 0;
 
+    /// Constructor (no results, no operands)
+    Swizzle();
+
     /// Constructor
     /// @param result the result value
     /// @param object the object being swizzled
@@ -60,6 +64,9 @@
     /// @returns the swizzle indices
     VectorRef<uint32_t> Indices() const { return indices_; }
 
+    /// @param indices the new swizzle indices
+    void SetIndices(VectorRef<uint32_t> indices) { indices_ = std::move(indices); }
+
     /// @returns the friendly name for the instruction
     std::string FriendlyName() const override { return "swizzle"; }