[ir][spirv-writer] Add support for return values

Bug: tint:1906
Change-Id: I73eb7ed2479c0f8051939163416c660c2f4faf05
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/134200
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir.cc b/src/tint/writer/spirv/ir/generator_impl_ir.cc
index 44bead9..9446cb0 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir.cc
@@ -332,11 +332,14 @@
         b->To(),
         [&](const ir::Block* blk) { current_function_.push_inst(spv::Op::OpBranch, {Label(blk)}); },
         [&](const ir::FunctionTerminator*) {
-            // TODO(jrprice): Handle the return value, which will be a branch argument.
             if (!b->Args().IsEmpty()) {
-                TINT_ICE(Writer, diagnostics_) << "unimplemented return value";
+                TINT_ASSERT(Writer, b->Args().Length() == 1u);
+                OperandList operands;
+                operands.push_back(Value(b->Args()[0]));
+                current_function_.push_inst(spv::Op::OpReturnValue, operands);
+            } else {
+                current_function_.push_inst(spv::Op::OpReturn, {});
             }
-            current_function_.push_inst(spv::Op::OpReturn, {});
         },
         [&](Default) {
             // A block may not have an outward branch (e.g. an unreachable merge
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
index 80f8c06..6d7756d 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
@@ -138,5 +138,22 @@
 )");
 }
 
+TEST_F(SpvGeneratorImplTest, Function_ReturnValue) {
+    auto* func = b.CreateFunction("foo", mod.types.i32());
+    func->StartTarget()->SetInstructions(
+        utils::Vector{b.Branch(func->EndTarget(), utils::Vector{b.Constant(i32(42))})});
+
+    generator_.EmitFunction(func);
+    EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
+%2 = OpTypeInt 32 1
+%3 = OpTypeFunction %2
+%5 = OpConstant %2 42
+%1 = OpFunction %2 None %3
+%4 = OpLabel
+OpReturnValue %5
+OpFunctionEnd
+)");
+}
+
 }  // namespace
 }  // namespace tint::writer::spirv