[tint][ir] Serialize UserCall

Change-Id: Ie005fba83b061cc3b964c038840e3ea82ab64fb6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/164741
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index db47200..63314b0 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -178,6 +178,9 @@
             case pb::InstructionKind::Var:
                 inst_out = mod_out_.instructions.Create<ir::Var>();
                 break;
+            case pb::InstructionKind::UserCall:
+                inst_out = mod_out_.instructions.Create<ir::UserCall>();
+                break;
             default:
                 TINT_UNIMPLEMENTED() << inst_in.kind();
                 break;
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index b0d8e35..3d11515 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -39,6 +39,7 @@
 #include "src/tint/lang/core/ir/let.h"
 #include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/core/ir/return.h"
+#include "src/tint/lang/core/ir/user_call.h"
 #include "src/tint/lang/core/ir/var.h"
 #include "src/tint/lang/core/type/array.h"
 #include "src/tint/lang/core/type/bool.h"
@@ -146,6 +147,7 @@
             [&](const ir::Let*) { return pb::InstructionKind::Let; },              //
             [&](const ir::Return*) { return pb::InstructionKind::Return; },        //
             [&](const ir::Var*) { return pb::InstructionKind::Var; },              //
+            [&](const ir::UserCall*) { return pb::InstructionKind::UserCall; },    //
             TINT_ICE_ON_NO_MATCH);
         inst_out->set_kind(kind);
         for (auto* operand : inst_in->Operands()) {
diff --git a/src/tint/lang/core/ir/binary/ir.proto b/src/tint/lang/core/ir/binary/ir.proto
index a7728b3..ef5c919 100644
--- a/src/tint/lang/core/ir/binary/ir.proto
+++ b/src/tint/lang/core/ir/binary/ir.proto
@@ -192,6 +192,7 @@
     Var = 7;
     Construct = 8;
     Access = 9;
+    UserCall = 10;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tint/lang/core/ir/binary/roundtrip_test.cc b/src/tint/lang/core/ir/binary/roundtrip_test.cc
index e9ca0df..68d67f9 100644
--- a/src/tint/lang/core/ir/binary/roundtrip_test.cc
+++ b/src/tint/lang/core/ir/binary/roundtrip_test.cc
@@ -221,5 +221,13 @@
     RUN_TEST();
 }
 
+TEST_F(IRBinaryRoundtripTest, UserCall) {
+    auto* fn_a = b.Function("A", ty.f32());
+    b.Append(fn_a->Block(), [&] { b.Return(fn_a, 42_f); });
+    auto* fn_b = b.Function("B", ty.f32());
+    b.Append(fn_b->Block(), [&] { b.Return(fn_b, b.Call(fn_a)); });
+    RUN_TEST();
+}
+
 }  // namespace
 }  // namespace tint::core::ir::binary
diff --git a/src/tint/lang/core/ir/user_call.cc b/src/tint/lang/core/ir/user_call.cc
index 698cb62..6cadb32 100644
--- a/src/tint/lang/core/ir/user_call.cc
+++ b/src/tint/lang/core/ir/user_call.cc
@@ -36,6 +36,10 @@
 
 namespace tint::core::ir {
 
+UserCall::UserCall() {
+    flags_.Add(Flag::kSequenced);
+}
+
 UserCall::UserCall(InstructionResult* result, Function* func, VectorRef<Value*> arguments) {
     flags_.Add(Flag::kSequenced);
     AddOperand(UserCall::kFunctionOperandOffset, func);
diff --git a/src/tint/lang/core/ir/user_call.h b/src/tint/lang/core/ir/user_call.h
index 4036208..a7a9b97 100644
--- a/src/tint/lang/core/ir/user_call.h
+++ b/src/tint/lang/core/ir/user_call.h
@@ -45,6 +45,9 @@
     /// The base offset in Operands() for the call arguments
     static constexpr size_t kArgsOperandOffset = 1;
 
+    /// Constructor (no results, no operands)
+    UserCall();
+
     /// Constructor
     /// @param result the result value
     /// @param func the function being called