[spirv-reader] Add OpLogicalNot

Bug: tint:3
Change-Id: I5565133c47a34be3ed9e10b97aa5dfca0eace502
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19884
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 78c5796..d69a144 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -50,7 +50,10 @@
     case SpvOpFNegate:
       *ast_unary_op = ast::UnaryOp::kNegation;
       return true;
-    // TODO(dneto): SpvOpNegate SpvOpNot SpvLogicalNot
+    case SpvOpLogicalNot:
+      // TODO(dneto): SpvOpNot
+      *ast_unary_op = ast::UnaryOp::kNot;
+      return true;
     default:
       break;
   }
diff --git a/src/reader/spirv/function_logical_test.cc b/src/reader/spirv/function_logical_test.cc
index a3e0b36..a0a1588 100644
--- a/src/reader/spirv/function_logical_test.cc
+++ b/src/reader/spirv/function_logical_test.cc
@@ -129,6 +129,35 @@
   return "bad case";
 }
 
+using SpvUnaryLogicalTest = SpvParserTestBase<::testing::Test>;
+
+TEST_F(SpvUnaryLogicalTest, LogicalNot_Scalar) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpLogicalNot %bool %true
+     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
+    __bool
+    {
+      UnaryOp{
+        not
+        ScalarConstructor{true}
+      }
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
 struct BinaryData {
   const std::string res_type;
   const std::string lhs;