[ir] Cleanup disassembler output

This CL expands the disassembler output and makes a bit more useful. The
case selector value is changed to an `ir::Constant` instead of the
`constant::Value` to make disassembly easier. The `BuilderImpl` is
updated to not fail in the face of missing implementation but continue
as best as possible.

Bug: tint:1718
Change-Id: I8b275a19bccbb02bb785d311778198bb0c9e0456
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116547
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index dbcad5e..ed4a156 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -45,6 +45,7 @@
 #include "src/tint/sem/expression.h"
 #include "src/tint/sem/module.h"
 #include "src/tint/sem/switch_statement.h"
+#include "src/tint/type/void.h"
 
 namespace tint::ir {
 namespace {
@@ -237,6 +238,8 @@
             diagnostics_.add_warning(
                 tint::diag::System::IR,
                 "unknown statement type: " + std::string(stmt->TypeInfo().name), stmt->source);
+            // TODO(dsinclair): This should return `false`, switch back when all
+            // the cases are handled.
             return true;
         });
 }
@@ -461,7 +464,7 @@
                 if (selector->IsDefault()) {
                     selectors.Push({nullptr});
                 } else {
-                    selectors.Push({selector->Value()->Clone(clone_ctx_)});
+                    selectors.Push({builder.Constant(selector->Value()->Clone(clone_ctx_))});
                 }
             }
 
@@ -575,7 +578,10 @@
             diagnostics_.add_warning(
                 tint::diag::System::IR,
                 "unknown expression type: " + std::string(expr->TypeInfo().name), expr->source);
-            return utils::Failure;
+            // TODO(dsinclair): This should return utils::Failure; Switch back
+            // once all the above cases are handled.
+            auto* v = builder.ir.types.Get<type::Void>();
+            return builder.Temp(v);
         });
 }
 
@@ -590,7 +596,10 @@
             diagnostics_.add_warning(tint::diag::System::IR,
                                      "unknown variable: " + std::string(var->TypeInfo().name),
                                      var->source);
-            return false;
+
+            // TODO(dsinclair): This should return `false`, switch back when all
+            // the cases are handled.
+            return true;
         });
 }
 
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index eb3811e..bc3a23e 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1125,12 +1125,14 @@
     auto* func = m.functions[0];
 
     ASSERT_EQ(1u, flow->cases[0].selectors.Length());
-    ASSERT_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
-    EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
+    ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+    EXPECT_EQ(0_i,
+              flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
 
     ASSERT_EQ(1u, flow->cases[1].selectors.Length());
-    ASSERT_TRUE(flow->cases[1].selectors[0].val->Is<constant::Scalar<tint::i32>>());
-    EXPECT_EQ(1_i, flow->cases[1].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
+    ASSERT_TRUE(flow->cases[1].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+    EXPECT_EQ(1_i,
+              flow->cases[1].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
 
     ASSERT_EQ(1u, flow->cases[2].selectors.Length());
     EXPECT_TRUE(flow->cases[2].selectors[0].IsDefault());
@@ -1227,8 +1229,9 @@
     auto* func = m.functions[0];
 
     ASSERT_EQ(1u, flow->cases[0].selectors.Length());
-    ASSERT_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
-    EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
+    ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+    EXPECT_EQ(0_i,
+              flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
 
     ASSERT_EQ(1u, flow->cases[1].selectors.Length());
     EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
@@ -1291,8 +1294,9 @@
     auto* func = m.functions[0];
 
     ASSERT_EQ(1u, flow->cases[0].selectors.Length());
-    ASSERT_TRUE(flow->cases[0].selectors[0].val->Is<constant::Scalar<tint::i32>>());
-    EXPECT_EQ(0_i, flow->cases[0].selectors[0].val->As<constant::Scalar<tint::i32>>()->ValueOf());
+    ASSERT_TRUE(flow->cases[0].selectors[0].val->value->Is<constant::Scalar<tint::i32>>());
+    EXPECT_EQ(0_i,
+              flow->cases[0].selectors[0].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
 
     ASSERT_EQ(1u, flow->cases[1].selectors.Length());
     EXPECT_TRUE(flow->cases[1].selectors[0].IsDefault());
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index e65bcca..d3201c0 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -62,6 +62,7 @@
 
 void Disassembler::EmitBlockInstructions(const Block* b) {
     for (const auto* instr : b->instructions) {
+        Indent();
         instr->ToString(out_, mod_.symbols) << std::endl;
     }
 }
@@ -85,7 +86,8 @@
     tint::Switch(
         node,
         [&](const ir::Function* f) {
-            Indent() << "%" << GetIdForNode(f) << " = Function" << std::endl;
+            Indent() << "%bb" << GetIdForNode(f) << " = Function " << mod_.symbols.NameFor(f->name)
+                     << std::endl;
 
             {
                 ScopedIndent func_indent(&indent_size_);
@@ -95,76 +97,92 @@
             Walk(f->end_target);
         },
         [&](const ir::Block* b) {
-            Indent() << "%" << GetIdForNode(b) << " = Block" << std::endl;
+            Indent() << "%bb" << GetIdForNode(b) << " = Block" << std::endl;
             EmitBlockInstructions(b);
 
             if (b->branch.target->Is<Terminator>()) {
-                Indent() << "Return ";
+                Indent() << "Return";
             } else {
-                Indent() << "Branch ";
+                Indent() << "BranchTo "
+                         << "%bb" << GetIdForNode(b->branch.target);
             }
-            out_ << GetIdForNode(b->branch.target);
-
+            out_ << " (";
             for (const auto* v : b->branch.args) {
-                out_ << " ";
+                if (v != b->branch.args.Front()) {
+                    out_ << ", ";
+                }
                 v->ToString(out_, mod_.symbols);
             }
-            out_ << std::endl;
+            out_ << ")" << std::endl << std::endl;
 
             Walk(b->branch.target);
         },
         [&](const ir::Switch* s) {
-            Indent() << "%" << GetIdForNode(s) << " = Switch (" << s->condition << ")" << std::endl;
+            Indent() << "%bb" << GetIdForNode(s) << " = Switch (";
+            s->condition->ToString(out_, mod_.symbols);
+            out_ << ")" << std::endl;
 
             {
                 ScopedIndent switch_indent(&indent_size_);
                 ScopedStopNode scope(&stop_nodes_, s->merge.target);
                 for (const auto& c : s->cases) {
-                    Indent() << "Case" << std::endl;
+                    Indent() << "# Case ";
+                    for (const auto& selector : c.selectors) {
+                        if (selector.IsDefault()) {
+                            out_ << "default ";
+                        } else {
+                            selector.val->ToString(out_, mod_.symbols);
+                        }
+                    }
+                    out_ << std::endl;
                     ScopedIndent case_indent(&indent_size_);
                     Walk(c.start.target);
                 }
             }
 
-            Indent() << "Switch Merge" << std::endl;
+            Indent() << "# Switch Merge" << std::endl;
             Walk(s->merge.target);
         },
         [&](const ir::If* i) {
-            Indent() << "%" << GetIdForNode(i) << " = if (" << i->condition << ")" << std::endl;
+            Indent() << "%bb" << GetIdForNode(i) << " = if (";
+            i->condition->ToString(out_, mod_.symbols);
+            out_ << ")" << std::endl;
+
             {
                 ScopedIndent if_indent(&indent_size_);
                 ScopedStopNode scope(&stop_nodes_, i->merge.target);
 
-                Indent() << "true branch" << std::endl;
+                Indent() << "# true branch" << std::endl;
                 Walk(i->true_.target);
 
-                Indent() << "false branch" << std::endl;
+                Indent() << "# false branch" << std::endl;
                 Walk(i->false_.target);
             }
 
-            Indent() << "if merge" << std::endl;
+            Indent() << "# if merge" << std::endl;
             Walk(i->merge.target);
         },
         [&](const ir::Loop* l) {
-            Indent() << "%" << GetIdForNode(l) << " = loop" << std::endl;
+            Indent() << "%bb" << GetIdForNode(l) << " = loop" << std::endl;
             {
                 ScopedStopNode loop_scope(&stop_nodes_, l->merge.target);
                 ScopedIndent loop_indent(&indent_size_);
                 {
                     ScopedStopNode inner_scope(&stop_nodes_, l->continuing.target);
-                    Indent() << "loop start" << std::endl;
+                    Indent() << "# loop start" << std::endl;
                     Walk(l->start.target);
                 }
 
-                Indent() << "loop continuing" << std::endl;
+                Indent() << "# loop continuing" << std::endl;
                 ScopedIndent continuing_indent(&indent_size_);
                 Walk(l->continuing.target);
             }
 
-            Indent() << "loop merge" << std::endl;
+            Indent() << "# loop merge" << std::endl;
             Walk(l->merge.target);
         },
-        [&](const ir::Terminator*) { Indent() << "Function end" << std::endl; });
+        [&](const ir::Terminator*) { Indent() << "FunctionEnd" << std::endl
+                                              << std::endl; });
 }
 
 std::string Disassembler::Disassemble() {
diff --git a/src/tint/ir/switch.h b/src/tint/ir/switch.h
index 6d3a952..6ba1d4c 100644
--- a/src/tint/ir/switch.h
+++ b/src/tint/ir/switch.h
@@ -15,9 +15,9 @@
 #ifndef SRC_TINT_IR_SWITCH_H_
 #define SRC_TINT_IR_SWITCH_H_
 
-#include "src/tint/constant/value.h"
 #include "src/tint/ir/block.h"
 #include "src/tint/ir/branch.h"
+#include "src/tint/ir/constant.h"
 #include "src/tint/ir/flow_node.h"
 #include "src/tint/ir/value.h"
 
@@ -32,7 +32,7 @@
         bool IsDefault() const { return val == nullptr; }
 
         /// The selector value, or nullptr if this is the default selector
-        constant::Value* val = nullptr;
+        Constant* val = nullptr;
     };
 
     /// A case label in the struct