[spirv-reader] Add OpFNegate

Bug: tint:3
Change-Id: I081df8fd37750917ae15667954d1b3fabb799010
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19883
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index a97cba8..78c5796 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -47,6 +47,7 @@
 bool GetUnaryOp(SpvOp opcode, ast::UnaryOp* ast_unary_op) {
   switch (opcode) {
     case SpvOpSNegate:
+    case SpvOpFNegate:
       *ast_unary_op = ast::UnaryOp::kNegation;
       return true;
     // TODO(dneto): SpvOpNegate SpvOpNot SpvLogicalNot
diff --git a/src/reader/spirv/function_arithmetic_test.cc b/src/reader/spirv/function_arithmetic_test.cc
index acbfb28..b4aa51e 100644
--- a/src/reader/spirv/function_arithmetic_test.cc
+++ b/src/reader/spirv/function_arithmetic_test.cc
@@ -334,6 +334,64 @@
       << ToString(fe.ast_body());
 }
 
+TEST_F(SpvUnaryArithTest, FNegate_Scalar) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpFNegate %float %float_50
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+  Variable{
+    x_1
+    none
+    __f32
+    {
+      UnaryOp{
+        negation
+        ScalarConstructor{50.000000}
+      }
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryArithTest, FNegate_Vector) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpFNegate %v2float %v2float_50_60
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+  Variable{
+    x_1
+    none
+    __vec_2__f32
+    {
+      UnaryOp{
+        negation
+        TypeConstructor{
+          __vec_2__f32
+          ScalarConstructor{50.000000}
+          ScalarConstructor{60.000000}
+        }
+      }
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
 struct BinaryData {
   const std::string res_type;
   const std::string lhs;
@@ -1022,9 +1080,6 @@
                    "__vec_2__i32", AstFor("v2int_40_30"), "xor",
                    AstFor("v2uint_20_10")}));
 
-// TODO(dneto): OpSNegate
-// TODO(dneto): OpFNegate
-
 // TODO(dneto): OpSRem. Missing from WGSL
 // https://github.com/gpuweb/gpuweb/issues/702