[ir] Change unary not to a binary equal

This CL removes unary `not` and instead emits `x == false`. When coming
back out of IR we can detect the `== false` and convert back to a `!`.

Bug: tint:1928
Change-Id: I905493182533ac2787ab9fe9245c8b53d51c1298
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131580
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index 9b7fd07..6a96633 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -203,6 +203,25 @@
     EXPECT_EQ(2_i, rhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
 }
 
+TEST_F(IR_InstructionTest, CreateNot) {
+    auto& b = CreateEmptyBuilder();
+    const auto* inst =
+        b.builder.Not(b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(true));
+
+    ASSERT_TRUE(inst->Is<Binary>());
+    EXPECT_EQ(inst->GetKind(), Binary::Kind::kEqual);
+
+    ASSERT_TRUE(inst->LHS()->Is<Constant>());
+    auto lhs = inst->LHS()->As<Constant>()->value;
+    ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
+    EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
+
+    ASSERT_TRUE(inst->RHS()->Is<Constant>());
+    auto rhs = inst->RHS()->As<Constant>()->value;
+    ASSERT_TRUE(rhs->Is<constant::Scalar<bool>>());
+    EXPECT_FALSE(rhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
+}
+
 TEST_F(IR_InstructionTest, CreateShiftLeft) {
     auto& b = CreateEmptyBuilder();
 
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 8badd31..e826be4d 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -16,6 +16,8 @@
 
 #include <utility>
 
+#include "src/tint/constant/scalar.h"
+
 namespace tint::ir {
 
 Builder::Builder() {}
@@ -194,8 +196,8 @@
     return CreateUnary(Unary::Kind::kNegation, type, val);
 }
 
-Unary* Builder::Not(const type::Type* type, Value* val) {
-    return CreateUnary(Unary::Kind::kNot, type, val);
+Binary* Builder::Not(const type::Type* type, Value* val) {
+    return Equal(type, val, Constant(create<constant::Scalar<bool>>(type, false)));
 }
 
 ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) {
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index 24c20d0..ff01e2d 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -300,7 +300,7 @@
     /// @param type the result type of the expression
     /// @param val the value
     /// @returns the operation
-    Unary* Not(const type::Type* type, Value* val);
+    Binary* Not(const type::Type* type, Value* val);
 
     /// Creates a bitcast instruction
     /// @param type the result type of the bitcast
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index 2a42917..2d6530e 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -833,7 +833,7 @@
     auto* sem = program_->Sem().Get(expr);
     auto* ty = sem->Type()->Clone(clone_ctx_.type_ctx);
 
-    Unary* inst = nullptr;
+    Instruction* inst = nullptr;
     switch (expr->op) {
         case ast::UnaryOp::kAddressOf:
             inst = builder.AddressOf(ty, val.Get());
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index ffda493..ec17624 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -493,9 +493,6 @@
         case Unary::Kind::kNegation:
             out_ << "negation";
             break;
-        case Unary::Kind::kNot:
-            out_ << "not";
-            break;
     }
     out_ << " ";
     EmitValue(u->Val());
diff --git a/src/tint/ir/unary.h b/src/tint/ir/unary.h
index 297e48f1..64301d4 100644
--- a/src/tint/ir/unary.h
+++ b/src/tint/ir/unary.h
@@ -29,7 +29,6 @@
         kComplement,
         kIndirection,
         kNegation,
-        kNot,
     };
 
     /// Constructor
diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc
index ace90eb..e205d8f 100644
--- a/src/tint/ir/unary_test.cc
+++ b/src/tint/ir/unary_test.cc
@@ -87,20 +87,6 @@
     EXPECT_EQ(4_i, lhs->As<constant::Scalar<i32>>()->ValueAs<i32>());
 }
 
-TEST_F(IR_InstructionTest, CreateNot) {
-    auto& b = CreateEmptyBuilder();
-    const auto* inst =
-        b.builder.Not(b.builder.ir.types.Get<type::Bool>(), b.builder.Constant(true));
-
-    ASSERT_TRUE(inst->Is<Unary>());
-    EXPECT_EQ(inst->GetKind(), Unary::Kind::kNot);
-
-    ASSERT_TRUE(inst->Val()->Is<Constant>());
-    auto lhs = inst->Val()->As<Constant>()->value;
-    ASSERT_TRUE(lhs->Is<constant::Scalar<bool>>());
-    EXPECT_TRUE(lhs->As<constant::Scalar<bool>>()->ValueAs<bool>());
-}
-
 TEST_F(IR_InstructionTest, Unary_Usage) {
     auto& b = CreateEmptyBuilder();
     const auto* inst =