[spirv-reader][ir] Convert `OpFNegate` instruction.

This converts the SPIR-V `OpFNegate` instruction to an IR `negation`.

Bug: 391486356
Change-Id: I8a5bfd886f7b01058ac915ff0d37a7e7206c0f5b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/228134
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/spirv/reader/parser/BUILD.bazel b/src/tint/lang/spirv/reader/parser/BUILD.bazel
index 8523c40..f3f86ec 100644
--- a/src/tint/lang/spirv/reader/parser/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/parser/BUILD.bazel
@@ -97,6 +97,7 @@
     "misc_test.cc",
     "name_test.cc",
     "struct_test.cc",
+    "unary_test.cc",
     "var_test.cc",
   ],
   deps = [
diff --git a/src/tint/lang/spirv/reader/parser/BUILD.cmake b/src/tint/lang/spirv/reader/parser/BUILD.cmake
index 1c851ea..7b662b5 100644
--- a/src/tint/lang/spirv/reader/parser/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/parser/BUILD.cmake
@@ -106,6 +106,7 @@
   lang/spirv/reader/parser/misc_test.cc
   lang/spirv/reader/parser/name_test.cc
   lang/spirv/reader/parser/struct_test.cc
+  lang/spirv/reader/parser/unary_test.cc
   lang/spirv/reader/parser/var_test.cc
 )
 
diff --git a/src/tint/lang/spirv/reader/parser/BUILD.gn b/src/tint/lang/spirv/reader/parser/BUILD.gn
index b3e0f81..84094fc 100644
--- a/src/tint/lang/spirv/reader/parser/BUILD.gn
+++ b/src/tint/lang/spirv/reader/parser/BUILD.gn
@@ -105,6 +105,7 @@
         "misc_test.cc",
         "name_test.cc",
         "struct_test.cc",
+        "unary_test.cc",
         "var_test.cc",
       ]
       deps = [
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index adcc929..1bbef3d 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -958,6 +958,9 @@
                 case spv::Op::OpLogicalNot:
                     EmitUnary(inst, core::UnaryOp::kNot);
                     break;
+                case spv::Op::OpFNegate:
+                    EmitUnary(inst, core::UnaryOp::kNegation);
+                    break;
                 case spv::Op::OpNot:
                     EmitSpirvExplicitBuiltinCall(inst, spirv::BuiltinFn::kNot);
                     break;
diff --git a/src/tint/lang/spirv/reader/parser/unary_test.cc b/src/tint/lang/spirv/reader/parser/unary_test.cc
new file mode 100644
index 0000000..9f38780
--- /dev/null
+++ b/src/tint/lang/spirv/reader/parser/unary_test.cc
@@ -0,0 +1,110 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/spirv/reader/parser/helper_test.h"
+
+namespace tint::spirv::reader {
+namespace {
+
+struct UnaryCase {
+    std::string spirv_type;
+    std::string spirv_opcode;
+    std::string ir_type;
+    std::string ir;
+};
+std::string PrintBuiltinCase(testing::TestParamInfo<UnaryCase> bc) {
+    return bc.param.spirv_opcode + "_" + bc.param.spirv_type;
+}
+
+using UnaryTest = SpirvParserTestWithParam<UnaryCase>;
+
+TEST_P(UnaryTest, All) {
+    auto params = GetParam();
+    EXPECT_IR(R"(
+               OpCapability Shader
+               OpCapability Float16
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+       %void = OpTypeVoid
+        %i32 = OpTypeInt 32 1
+        %u32 = OpTypeInt 32 0
+        %f16 = OpTypeFloat 16
+        %f32 = OpTypeFloat 32
+      %vec3i = OpTypeVector %i32 3
+      %vec4u = OpTypeVector %u32 4
+      %vec3h = OpTypeVector %f16 3
+      %vec4f = OpTypeVector %f32 4
+    %ep_type = OpTypeFunction %void
+    %fn_type = OpTypeFunction %)" +
+                  params.spirv_type + " %" + params.spirv_type + " %" + params.spirv_type + R"(
+       %main = OpFunction %void None %ep_type
+ %main_start = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+        %foo = OpFunction %)" +
+                  params.spirv_type + " " + R"( None %fn_type
+        %lhs = OpFunctionParameter %)" +
+                  params.spirv_type + " " + R"(
+  %foo_start = OpLabel
+     %result = )" +
+                  params.spirv_opcode + R"( %)" + params.spirv_type + " " + R"( %lhs
+               OpReturnValue %result
+               OpFunctionEnd
+)",
+              R"(
+%main = @compute @workgroup_size(1u, 1u, 1u) func():void {
+  $B1: {
+    ret
+  }
+}
+%2 = func(%3:)" + params.ir_type +
+                  "):" + params.ir_type + R"( {
+  $B2: {
+    )" + params.ir +
+                  R"(
+    ret %4
+  }
+}
+)");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    SpirvParser,
+    UnaryTest,
+    testing::Values(
+        // OpFNegate
+        UnaryCase{"f16", "OpFNegate", "f16", "%4:f16 = negation %3"},
+        UnaryCase{"f32", "OpFNegate", "f32", "%4:f32 = negation %3"},
+
+        UnaryCase{"vec3h", "OpFNegate", "vec3<f16>", "%4:vec3<f16> = negation %3"},
+        UnaryCase{"vec4f", "OpFNegate", "vec4<f32>", "%4:vec4<f32> = negation %3"}),
+    PrintBuiltinCase);
+
+}  // namespace
+}  // namespace tint::spirv::reader