[ir] Make dump output more consistent.

This Cl updates the dump output for the IR to be a bit more consistent.
Brackets are removed, named calls are used in place of symbols. Trailing
commas cleaned up. Values have their type appended to make it clearer
what they are when a literal is emitted.

Bug: tint:1718
Change-Id: Ie202d4a4f8267d00b9af4864063b7133f4c7f324
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/130000
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ir/binary.cc b/src/tint/ir/binary.cc
index 9621b3e..d3e3548 100644
--- a/src/tint/ir/binary.cc
+++ b/src/tint/ir/binary.cc
@@ -31,67 +31,66 @@
 
 utils::StringStream& Binary::ToInstruction(utils::StringStream& out) const {
     ToValue(out) << " = ";
-    lhs_->ToValue(out) << " ";
 
     switch (GetKind()) {
         case Binary::Kind::kAdd:
-            out << "+";
+            out << "add";
             break;
         case Binary::Kind::kSubtract:
-            out << "-";
+            out << "sub";
             break;
         case Binary::Kind::kMultiply:
-            out << "*";
+            out << "mul";
             break;
         case Binary::Kind::kDivide:
-            out << "/";
+            out << "div";
             break;
         case Binary::Kind::kModulo:
-            out << "%";
+            out << "mod";
             break;
         case Binary::Kind::kAnd:
-            out << "&";
+            out << "bit_and";
             break;
         case Binary::Kind::kOr:
-            out << "|";
+            out << "bit_or";
             break;
         case Binary::Kind::kXor:
-            out << "^";
+            out << "bit_xor";
             break;
         case Binary::Kind::kLogicalAnd:
-            out << "&&";
+            out << "log_and";
             break;
         case Binary::Kind::kLogicalOr:
-            out << "||";
+            out << "log_or";
             break;
         case Binary::Kind::kEqual:
-            out << "==";
+            out << "eq";
             break;
         case Binary::Kind::kNotEqual:
-            out << "!=";
+            out << "neq";
             break;
         case Binary::Kind::kLessThan:
-            out << "<";
+            out << "lt";
             break;
         case Binary::Kind::kGreaterThan:
-            out << ">";
+            out << "gt";
             break;
         case Binary::Kind::kLessThanEqual:
-            out << "<=";
+            out << "lte";
             break;
         case Binary::Kind::kGreaterThanEqual:
-            out << ">=";
+            out << "gte";
             break;
         case Binary::Kind::kShiftLeft:
-            out << "<<";
+            out << "shiftl";
             break;
         case Binary::Kind::kShiftRight:
-            out << ">>";
+            out << "shiftr";
             break;
     }
     out << " ";
+    lhs_->ToValue(out) << ", ";
     rhs_->ToValue(out);
-
     return out;
 }
 
diff --git a/src/tint/ir/binary_test.cc b/src/tint/ir/binary_test.cc
index 5868c95..e03a61d 100644
--- a/src/tint/ir/binary_test.cc
+++ b/src/tint/ir/binary_test.cc
@@ -45,7 +45,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 & 2");
+    EXPECT_EQ(str.str(), "%1(i32) = bit_and 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateOr) {
@@ -69,7 +69,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 | 2");
+    EXPECT_EQ(str.str(), "%1(i32) = bit_or 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateXor) {
@@ -93,7 +93,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 ^ 2");
+    EXPECT_EQ(str.str(), "%1(i32) = bit_xor 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateLogicalAnd) {
@@ -117,7 +117,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 && 2");
+    EXPECT_EQ(str.str(), "%1(bool) = log_and 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateLogicalOr) {
@@ -141,7 +141,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 || 2");
+    EXPECT_EQ(str.str(), "%1(bool) = log_or 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateEqual) {
@@ -165,7 +165,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 == 2");
+    EXPECT_EQ(str.str(), "%1(bool) = eq 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateNotEqual) {
@@ -189,7 +189,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 != 2");
+    EXPECT_EQ(str.str(), "%1(bool) = neq 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateLessThan) {
@@ -213,7 +213,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 < 2");
+    EXPECT_EQ(str.str(), "%1(bool) = lt 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateGreaterThan) {
@@ -237,7 +237,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 > 2");
+    EXPECT_EQ(str.str(), "%1(bool) = gt 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateLessThanEqual) {
@@ -261,7 +261,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 <= 2");
+    EXPECT_EQ(str.str(), "%1(bool) = lte 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateGreaterThanEqual) {
@@ -285,7 +285,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = 4 >= 2");
+    EXPECT_EQ(str.str(), "%1(bool) = gte 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateShiftLeft) {
@@ -309,7 +309,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 << 2");
+    EXPECT_EQ(str.str(), "%1(i32) = shiftl 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateShiftRight) {
@@ -333,7 +333,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 >> 2");
+    EXPECT_EQ(str.str(), "%1(i32) = shiftr 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateAdd) {
@@ -357,7 +357,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 + 2");
+    EXPECT_EQ(str.str(), "%1(i32) = add 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateSubtract) {
@@ -381,7 +381,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 - 2");
+    EXPECT_EQ(str.str(), "%1(i32) = sub 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateMultiply) {
@@ -405,7 +405,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 * 2");
+    EXPECT_EQ(str.str(), "%1(i32) = mul 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateDivide) {
@@ -429,7 +429,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 / 2");
+    EXPECT_EQ(str.str(), "%1(i32) = div 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, CreateModulo) {
@@ -453,7 +453,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = 4 % 2");
+    EXPECT_EQ(str.str(), "%1(i32) = mod 4i, 2i");
 }
 
 TEST_F(IR_InstructionTest, Binary_Usage) {
diff --git a/src/tint/ir/bitcast.cc b/src/tint/ir/bitcast.cc
index dffbf21..70f412c 100644
--- a/src/tint/ir/bitcast.cc
+++ b/src/tint/ir/bitcast.cc
@@ -25,9 +25,8 @@
 Bitcast::~Bitcast() = default;
 
 utils::StringStream& Bitcast::ToInstruction(utils::StringStream& out) const {
-    ToValue(out) << " = bitcast(";
+    ToValue(out) << " = bitcast ";
     EmitArgs(out);
-    out << ")";
     return out;
 }
 
diff --git a/src/tint/ir/bitcast_test.cc b/src/tint/ir/bitcast_test.cc
index f973b27..a70fb92 100644
--- a/src/tint/ir/bitcast_test.cc
+++ b/src/tint/ir/bitcast_test.cc
@@ -39,7 +39,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = bitcast(4)");
+    EXPECT_EQ(str.str(), "%1(i32) = bitcast 4i");
 }
 
 TEST_F(IR_InstructionTest, Bitcast_Usage) {
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index e83d43a..3981355 100644
--- a/src/tint/ir/block.h
+++ b/src/tint/ir/block.h
@@ -33,7 +33,7 @@
 
     /// @returns true if this is a dead block. This can happen in the case like a loop merge block
     /// which is never reached.
-    bool IsDead() const { return branch.target == nullptr; }
+    bool IsDead() const override { return branch.target == nullptr; }
 
     /// The node this block branches too.
     Branch branch = {};
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 6efd69c..3cd3c60 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -42,10 +42,10 @@
     EXPECT_EQ(1u, f->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, f->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function f
-  %bb1 = Block
-  Return ()
-FunctionEnd
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func f
+  %fn1 = block
+  ret
+func_end
 
 )");
 }
@@ -88,23 +88,23 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = if (true)
+  %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
     # true branch
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn5
 
     # false branch
-    %bb5 = Block
-    BranchTo %bb4 ()
+    %fn4 = block
+    branch %fn5
 
   # if merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -136,22 +136,22 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = if (true)
+  %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
     # true branch
-    %bb3 = Block
-    Return ()
+    %fn3 = block
+    ret
     # false branch
-    %bb4 = Block
-    BranchTo %bb5 ()
+    %fn4 = block
+    branch %fn5
 
   # if merge
-  %bb5 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -183,22 +183,22 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = if (true)
+  %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
     # true branch
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn5
 
     # false branch
-    %bb5 = Block
-    Return ()
+    %fn4 = block
+    ret
   # if merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -230,18 +230,18 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = if (true)
+  %fn2 = if true [t: %fn3, f: %fn4]
     # true branch
-    %bb3 = Block
-    Return ()
+    %fn3 = block
+    ret
     # false branch
-    %bb4 = Block
-    Return ()
-FunctionEnd
+    %fn4 = block
+    ret
+func_end
 
 )");
 }
@@ -273,36 +273,32 @@
     ASSERT_NE(loop_flow->continuing.target, nullptr);
     ASSERT_NE(loop_flow->merge.target, nullptr);
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = if (true)
+  %fn2 = if true [t: %fn3, f: %fn4, m: %fn5]
     # true branch
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn6
 
-    %bb4 = loop
+    %fn6 = loop [s: %fn7, m: %fn8]
       # loop start
-      %bb5 = Block
-      BranchTo %bb6 ()
-
-      # loop continuing
-      %bb7 = Block
-      BranchTo %bb5 ()
+      %fn7 = block
+      branch %fn8
 
     # loop merge
-    %bb6 = Block
-    BranchTo %bb8 ()
+    %fn8 = block
+    branch %fn5
 
     # false branch
-    %bb9 = Block
-    BranchTo %bb8 ()
+    %fn4 = block
+    branch %fn5
 
   # if merge
-  %bb8 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -334,23 +330,19 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, m: %fn4]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
-
-    # loop continuing
-    %bb5 = Block
-    BranchTo %bb3 ()
+    %fn3 = block
+    branch %fn4
 
   # loop merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -396,36 +388,36 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn6
 
-    %bb4 = if (true)
+    %fn6 = if true [t: %fn7, f: %fn8, m: %fn9]
       # true branch
-      %bb5 = Block
-      BranchTo %bb6 ()
+      %fn7 = block
+      branch %fn5
 
       # false branch
-      %bb7 = Block
-      BranchTo %bb8 ()
+      %fn8 = block
+      branch %fn9
 
     # if merge
-    %bb8 = Block
-    BranchTo %bb9 ()
+    %fn9 = block
+    branch %fn4
 
     # loop continuing
-    %bb9 = Block
-    BranchTo %bb3 ()
+    %fn4 = block
+    branch %fn3
 
   # loop merge
-  %bb6 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -471,36 +463,36 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn4
 
     # loop continuing
-    %bb4 = Block
-    BranchTo %bb5 ()
+    %fn4 = block
+    branch %fn6
 
-    %bb5 = if (true)
+    %fn6 = if true [t: %fn7, f: %fn8, m: %fn9]
       # true branch
-      %bb6 = Block
-      BranchTo %bb7 ()
+      %fn7 = block
+      branch %fn5
 
       # false branch
-      %bb8 = Block
-      BranchTo %bb9 ()
+      %fn8 = block
+      branch %fn9
 
     # if merge
-    %bb9 = Block
-    BranchTo %bb3 ()
+    %fn9 = block
+    branch %fn3
 
   # loop merge
-  %bb7 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -546,34 +538,32 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, c: %fn4]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn5
 
-    %bb4 = if (true)
+    %fn5 = if true [t: %fn6, f: %fn7, m: %fn8]
       # true branch
-      %bb5 = Block
-      Return ()
+      %fn6 = block
+      ret
       # false branch
-      %bb6 = Block
-      BranchTo %bb7 ()
+      %fn7 = block
+      branch %fn8
 
     # if merge
-    %bb7 = Block
-    BranchTo %bb8 ()
+    %fn8 = block
+    branch %fn4
 
     # loop continuing
-    %bb8 = Block
-    BranchTo %bb3 ()
+    %fn4 = block
+    branch %fn3
 
-  # loop merge
-  # Dead
-FunctionEnd
+func_end
 
 )");
 }
@@ -605,21 +595,15 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3]
     # loop start
-    %bb3 = Block
-    Return ()
-    # loop continuing
-    %bb4 = Block
-    BranchTo %bb3 ()
-
-  # loop merge
-  # Dead
-FunctionEnd
+    %fn3 = block
+    ret
+func_end
 
 )");
 }
@@ -629,6 +613,9 @@
     // `ast_if` below), it doesn't get emitted as there is no way to reach the
     // loop merge due to the loop itself doing a `return`. This is why the
     // loop merge gets marked as Dead and the `ast_if` doesn't appear.
+    //
+    // Similar, the continuing block goes away as there is no way to get there, so it's treated
+    // as dead code and dropped.
     auto* ast_break_if = BreakIf(true);
     auto* ast_loop = Loop(Block(Return()), Block(ast_break_if));
     auto* ast_if = If(true, Block(Return()));
@@ -670,34 +657,15 @@
     // This is 1 because only the loop branch happens. The subsequent if return is dead code.
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3]
     # loop start
-    %bb3 = Block
-    Return ()
-    # loop continuing
-    %bb4 = Block
-    BranchTo %bb5 ()
-
-    %bb5 = if (true)
-      # true branch
-      %bb6 = Block
-      BranchTo %bb7 ()
-
-      # false branch
-      %bb8 = Block
-      BranchTo %bb9 ()
-
-    # if merge
-    %bb9 = Block
-    BranchTo %bb3 ()
-
-  # loop merge
-  # Dead
-FunctionEnd
+    %fn3 = block
+    ret
+func_end
 
 )");
 }
@@ -743,32 +711,28 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, m: %fn4]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn5
 
-    %bb4 = if (true)
+    %fn5 = if true [t: %fn6, f: %fn7]
       # true branch
-      %bb5 = Block
-      BranchTo %bb6 ()
+      %fn6 = block
+      branch %fn4
 
       # false branch
-      %bb7 = Block
-      BranchTo %bb6 ()
-
-    # loop continuing
-    %bb8 = Block
-    BranchTo %bb3 ()
+      %fn7 = block
+      branch %fn4
 
   # loop merge
-  %bb6 = Block
-  Return ()
-FunctionEnd
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -893,114 +857,110 @@
     EXPECT_EQ(1u, func->start_target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn6
 
-    %bb4 = loop
+    %fn6 = loop [s: %fn7, c: %fn8, m: %fn9]
       # loop start
-      %bb5 = Block
-      BranchTo %bb6 ()
+      %fn7 = block
+      branch %fn10
 
-      %bb6 = if (true)
+      %fn10 = if true [t: %fn11, f: %fn12, m: %fn13]
         # true branch
-        %bb7 = Block
-        BranchTo %bb8 ()
+        %fn11 = block
+        branch %fn9
 
         # false branch
-        %bb9 = Block
-        BranchTo %bb10 ()
+        %fn12 = block
+        branch %fn13
 
       # if merge
-      %bb10 = Block
-      BranchTo %bb11 ()
+      %fn13 = block
+      branch %fn14
 
-      %bb11 = if (true)
+      %fn14 = if true [t: %fn15, f: %fn16, m: %fn17]
         # true branch
-        %bb12 = Block
-        BranchTo %bb13 ()
+        %fn15 = block
+        branch %fn8
 
         # false branch
-        %bb14 = Block
-        BranchTo %bb15 ()
+        %fn16 = block
+        branch %fn17
 
       # if merge
-      %bb15 = Block
-      BranchTo %bb13 ()
+      %fn17 = block
+      branch %fn8
 
       # loop continuing
-      %bb13 = Block
-      BranchTo %bb16 ()
+      %fn8 = block
+      branch %fn18
 
-      %bb16 = loop
+      %fn18 = loop [s: %fn19, m: %fn20]
         # loop start
-        %bb17 = Block
-        BranchTo %bb18 ()
-
-        # loop continuing
-        %bb19 = Block
-        BranchTo %bb17 ()
+        %fn19 = block
+        branch %fn20
 
       # loop merge
-      %bb18 = Block
-      BranchTo %bb20 ()
+      %fn20 = block
+      branch %fn21
 
-      %bb20 = loop
+      %fn21 = loop [s: %fn22, c: %fn23, m: %fn24]
         # loop start
-        %bb21 = Block
-        BranchTo %bb22 ()
+        %fn22 = block
+        branch %fn23
 
         # loop continuing
-        %bb22 = Block
-        BranchTo %bb23 ()
+        %fn23 = block
+        branch %fn25
 
-        %bb23 = if (true)
+        %fn25 = if true [t: %fn26, f: %fn27, m: %fn28]
           # true branch
-          %bb24 = Block
-          BranchTo %bb25 ()
+          %fn26 = block
+          branch %fn24
 
           # false branch
-          %bb26 = Block
-          BranchTo %bb27 ()
+          %fn27 = block
+          branch %fn28
 
         # if merge
-        %bb27 = Block
-        BranchTo %bb21 ()
+        %fn28 = block
+        branch %fn22
 
       # loop merge
-      %bb25 = Block
-      BranchTo %bb5 ()
+      %fn24 = block
+      branch %fn7
 
     # loop merge
-    %bb8 = Block
-    BranchTo %bb28 ()
+    %fn9 = block
+    branch %fn29
 
-    %bb28 = if (true)
+    %fn29 = if true [t: %fn30, f: %fn31, m: %fn32]
       # true branch
-      %bb29 = Block
-      BranchTo %bb30 ()
+      %fn30 = block
+      branch %fn5
 
       # false branch
-      %bb31 = Block
-      BranchTo %bb32 ()
+      %fn31 = block
+      branch %fn32
 
     # if merge
-    %bb32 = Block
-    BranchTo %bb33 ()
+    %fn32 = block
+    branch %fn4
 
     # loop continuing
-    %bb33 = Block
-    BranchTo %bb3 ()
+    %fn4 = block
+    branch %fn3
 
   # loop merge
-  %bb30 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -1041,36 +1001,36 @@
     EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
     EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, c: %fn4, m: %fn5]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn6
 
-    %bb4 = if (false)
+    %fn6 = if false [t: %fn7, f: %fn8, m: %fn9]
       # true branch
-      %bb5 = Block
-      BranchTo %bb6 ()
+      %fn7 = block
+      branch %fn9
 
       # false branch
-      %bb7 = Block
-      BranchTo %bb8 ()
+      %fn8 = block
+      branch %fn5
 
     # if merge
-    %bb6 = Block
-    BranchTo %bb9 ()
+    %fn9 = block
+    branch %fn4
 
     # loop continuing
-    %bb9 = Block
-    BranchTo %bb3 ()
+    %fn4 = block
+    branch %fn3
 
   # loop merge
-  %bb8 = Block
-  Return ()
-FunctionEnd
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -1111,35 +1071,31 @@
     EXPECT_EQ(1u, if_flow->false_.target->inbound_branches.Length());
     EXPECT_EQ(1u, if_flow->merge.target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, m: %fn4]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
+    %fn3 = block
+    branch %fn5
 
-    %bb4 = if (true)
+    %fn5 = if true [t: %fn6, f: %fn7, m: %fn8]
       # true branch
-      %bb5 = Block
-      BranchTo %bb6 ()
+      %fn6 = block
+      branch %fn8
 
       # false branch
-      %bb7 = Block
-      BranchTo %bb8 ()
+      %fn7 = block
+      branch %fn4
 
     # if merge
-    %bb6 = Block
-    Return ()
-    # loop continuing
-    %bb9 = Block
-    BranchTo %bb3 ()
-
+    %fn8 = block
+    ret
   # loop merge
-  %bb8 = Block
-  Return ()
-FunctionEnd
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -1222,23 +1178,19 @@
     EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = loop
+  %fn2 = loop [s: %fn3, m: %fn4]
     # loop start
-    %bb3 = Block
-    BranchTo %bb4 ()
-
-    # loop continuing
-    %bb5 = Block
-    BranchTo %bb3 ()
+    %fn3 = block
+    branch %fn4
 
   # loop merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -1285,27 +1237,83 @@
     EXPECT_EQ(3u, flow->merge.target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = Switch (1)
-    # Case 0
-    %bb3 = Block
-    BranchTo %bb4 ()
+  %fn2 = switch 1i [c: (0i, %fn3), c: (1i, %fn4), c: (default, %fn5), m: %fn6]
+    # case 0i
+    %fn3 = block
+    branch %fn6
 
-    # Case 1
-    %bb5 = Block
-    BranchTo %bb4 ()
+    # case 1i
+    %fn4 = block
+    branch %fn6
 
-    # Case default
-    %bb6 = Block
-    BranchTo %bb4 ()
+    # case default
+    %fn5 = block
+    branch %fn6
 
-  # Switch Merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  # switch merge
+  %fn6 = block
+  ret
+func_end
+
+)");
+}
+
+TEST_F(IR_BuilderImplTest, Switch_MultiSelector) {
+    auto* ast_switch = Switch(
+        1_i,
+        utils::Vector{Case(
+            utils::Vector{CaseSelector(0_i), CaseSelector(1_i), DefaultCaseSelector()}, Block())});
+
+    WrapInFunction(ast_switch);
+
+    auto r = Build();
+    ASSERT_TRUE(r) << Error();
+    auto m = r.Move();
+
+    auto* ir_switch = FlowNodeForAstNode(ast_switch);
+    ASSERT_NE(ir_switch, nullptr);
+    ASSERT_TRUE(ir_switch->Is<ir::Switch>());
+
+    auto* flow = ir_switch->As<ir::Switch>();
+    ASSERT_NE(flow->merge.target, nullptr);
+    ASSERT_EQ(1u, flow->cases.Length());
+
+    ASSERT_EQ(1u, m.functions.Length());
+    auto* func = m.functions[0];
+
+    ASSERT_EQ(3u, flow->cases[0].selectors.Length());
+    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_TRUE(flow->cases[0].selectors[1].val->value->Is<constant::Scalar<tint::i32>>());
+    EXPECT_EQ(1_i,
+              flow->cases[0].selectors[1].val->value->As<constant::Scalar<tint::i32>>()->ValueOf());
+
+    EXPECT_TRUE(flow->cases[0].selectors[2].IsDefault());
+
+    EXPECT_EQ(1u, flow->inbound_branches.Length());
+    EXPECT_EQ(1u, flow->cases[0].start.target->inbound_branches.Length());
+    EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
+    EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
+
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
+
+  %fn2 = switch 1i [c: (0i 1i default, %fn3), m: %fn4]
+    # case 0i 1i default
+    %fn3 = block
+    branch %fn4
+
+  # switch merge
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -1337,19 +1345,19 @@
     EXPECT_EQ(1u, flow->merge.target->inbound_branches.Length());
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = Switch (1)
-    # Case default
-    %bb3 = Block
-    BranchTo %bb4 ()
+  %fn2 = switch 1i [c: (default, %fn3), m: %fn4]
+    # case default
+    %fn3 = block
+    branch %fn4
 
-  # Switch Merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  # switch merge
+  %fn4 = block
+  ret
+func_end
 
 )");
 }
@@ -1390,23 +1398,23 @@
     // This is 1 because the if is dead-code eliminated and the return doesn't happen.
     EXPECT_EQ(1u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = Switch (1)
-    # Case 0
-    %bb3 = Block
-    BranchTo %bb4 ()
+  %fn2 = switch 1i [c: (0i, %fn3), c: (default, %fn4), m: %fn5]
+    # case 0i
+    %fn3 = block
+    branch %fn5
 
-    # Case default
-    %bb5 = Block
-    BranchTo %bb4 ()
+    # case default
+    %fn4 = block
+    branch %fn5
 
-  # Switch Merge
-  %bb4 = Block
-  Return ()
-FunctionEnd
+  # switch merge
+  %fn5 = block
+  ret
+func_end
 
 )");
 }
@@ -1449,20 +1457,18 @@
     EXPECT_EQ(0u, flow->merge.target->inbound_branches.Length());
     EXPECT_EQ(2u, func->end_target->inbound_branches.Length());
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  BranchTo %bb2 ()
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  branch %fn2
 
-  %bb2 = Switch (1)
-    # Case 0
-    %bb3 = Block
-    Return ()
-    # Case default
-    %bb4 = Block
-    Return ()
-  # Switch Merge
-  # Dead
-FunctionEnd
+  %fn2 = switch 1i [c: (0i, %fn3), c: (default, %fn4)]
+    # case 0i
+    %fn3 = block
+    ret
+    # case default
+    %fn4 = block
+    ret
+func_end
 
 )");
 }
@@ -1565,8 +1571,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) + 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = add %1(u32), 4u
 )");
 }
 
@@ -1583,8 +1589,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) - 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = sub %1(u32), 4u
 )");
 }
 
@@ -1601,8 +1607,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) * 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = mul %1(u32), 4u
 )");
 }
 
@@ -1619,8 +1625,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) / 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = div %1(u32), 4u
 )");
 }
 
@@ -1637,8 +1643,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) % 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = mod %1(u32), 4u
 )");
 }
 
@@ -1655,8 +1661,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) & 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_and %1(u32), 4u
 )");
 }
 
@@ -1673,8 +1679,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) | 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_or %1(u32), 4u
 )");
 }
 
@@ -1691,8 +1697,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) ^ 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = bit_xor %1(u32), 4u
 )");
 }
 
@@ -1709,8 +1715,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(bool) = call(my_func, )
-%2(bool) = %1(bool) && false
+    EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func
+%2(bool) = log_and %1(bool), false
 )");
 }
 
@@ -1727,8 +1733,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(bool) = call(my_func, )
-%2(bool) = %1(bool) || true
+    EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func
+%2(bool) = log_or %1(bool), true
 )");
 }
 
@@ -1745,8 +1751,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) == 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = eq %1(u32), 4u
 )");
 }
 
@@ -1763,8 +1769,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) != 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = neq %1(u32), 4u
 )");
 }
 
@@ -1781,8 +1787,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) < 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = lt %1(u32), 4u
 )");
 }
 
@@ -1799,8 +1805,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) > 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = gt %1(u32), 4u
 )");
 }
 
@@ -1817,8 +1823,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) <= 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = lte %1(u32), 4u
 )");
 }
 
@@ -1835,8 +1841,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(bool) = %1(u32) >= 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(bool) = gte %1(u32), 4u
 )");
 }
 
@@ -1853,8 +1859,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) << 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = shiftl %1(u32), 4u
 )");
 }
 
@@ -1871,8 +1877,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(u32) = call(my_func, )
-%2(u32) = %1(u32) >> 4
+    EXPECT_EQ(d.AsString(), R"(%1(u32) = call my_func
+%2(u32) = shiftr %1(u32), 4u
 )");
 }
 
@@ -1891,14 +1897,14 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(f32) = call(my_func, )
-%2(bool) = %1(f32) < 2.0
-%3(f32) = call(my_func, )
-%4(f32) = call(my_func, )
-%5(f32) = 2.29999995231628417969 * %4(f32)
-%6(f32) = %3(f32) / %5(f32)
-%7(bool) = 2.5 > %6(f32)
-%8(bool) = %2(bool) && %7(bool)
+    EXPECT_EQ(d.AsString(), R"(%1(f32) = call my_func
+%2(bool) = lt %1(f32), 2.0f
+%3(f32) = call my_func
+%4(f32) = call my_func
+%5(f32) = mul 2.29999995231628417969f, %4(f32)
+%6(f32) = div %3(f32), %5(f32)
+%7(bool) = gt 2.5f, %6(f32)
+%8(bool) = log_and %2(bool), %7(bool)
 )");
 }
 
@@ -1916,7 +1922,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(bool) = call(my_func, false)
+    EXPECT_EQ(d.AsString(), R"(%1(bool) = call my_func, false
 )");
 }
 
@@ -1934,8 +1940,8 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(f32) = call(my_func, )
-%2(f32) = bitcast(%1(f32))
+    EXPECT_EQ(d.AsString(), R"(%1(f32) = call my_func
+%2(f32) = bitcast %1(f32)
 )");
 }
 
@@ -1960,7 +1966,7 @@
 TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) {
     Func("my_func", utils::Vector{Param("p", ty.f32())}, ty.void_(), utils::Empty);
 
-    auto* stmt = CallStmt(Call("my_func", Mul(2_f, 3_f)));
+    auto* stmt = CallStmt(Call("my_func", Mul(2_a, 3_a)));
     WrapInFunction(stmt);
 
     auto& b = CreateBuilder();
@@ -1971,7 +1977,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(void) = call(my_func, 6.0)
+    EXPECT_EQ(d.AsString(), R"(%1(void) = call my_func, 6.0f
 )");
 }
 
@@ -1990,7 +1996,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%1(vec3<f32>) = construct()
+    EXPECT_EQ(d.AsString(), R"(%1(vec3<f32>) = construct
 )");
 }
 
@@ -2008,7 +2014,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%2(vec3<f32>) = construct(2.0, 3.0, %1(void))
+    EXPECT_EQ(d.AsString(), R"(%2(vec3<f32>) = construct 2.0f, 3.0f, %1(void)
 )");
 }
 
@@ -2026,7 +2032,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%2(f32) = convert(i32, %1(void))
+    EXPECT_EQ(d.AsString(), R"(%2(f32) = convert i32, %1(void)
 )");
 }
 
@@ -2039,10 +2045,10 @@
     ASSERT_TRUE(r) << Error();
     auto m = r.Move();
 
-    EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
-  %bb1 = Block
-  Return (2.0)
-FunctionEnd
+    EXPECT_EQ(Disassemble(m), R"(%fn0 = func test_function
+  %fn1 = block
+  ret 2.0f
+func_end
 
 )");
 }
@@ -2061,7 +2067,7 @@
 
     Disassembler d(b.builder.ir);
     d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
-    EXPECT_EQ(d.AsString(), R"(%2(f32) = asin(%1(void))
+    EXPECT_EQ(d.AsString(), R"(%2(f32) = asin %1(void)
 )");
 }
 
diff --git a/src/tint/ir/builtin.cc b/src/tint/ir/builtin.cc
index 54d2b98..54cf882 100644
--- a/src/tint/ir/builtin.cc
+++ b/src/tint/ir/builtin.cc
@@ -29,9 +29,8 @@
 Builtin::~Builtin() = default;
 
 utils::StringStream& Builtin::ToInstruction(utils::StringStream& out) const {
-    ToValue(out) << " = " << builtin::str(func_) << "(";
+    ToValue(out) << " = " << builtin::str(func_) << " ";
     EmitArgs(out);
-    out << ")";
     return out;
 }
 
diff --git a/src/tint/ir/constant.cc b/src/tint/ir/constant.cc
index e96415f..0666e91 100644
--- a/src/tint/ir/constant.cc
+++ b/src/tint/ir/constant.cc
@@ -35,27 +35,33 @@
             c,
             [&](const constant::Scalar<AFloat>* scalar) { out << scalar->ValueAs<AFloat>().value; },
             [&](const constant::Scalar<AInt>* scalar) { out << scalar->ValueAs<AInt>().value; },
-            [&](const constant::Scalar<i32>* scalar) { out << scalar->ValueAs<i32>().value; },
-            [&](const constant::Scalar<u32>* scalar) { out << scalar->ValueAs<u32>().value; },
-            [&](const constant::Scalar<f32>* scalar) { out << scalar->ValueAs<f32>().value; },
-            [&](const constant::Scalar<f16>* scalar) { out << scalar->ValueAs<f16>().value; },
+            [&](const constant::Scalar<i32>* scalar) {
+                out << scalar->ValueAs<i32>().value << "i";
+            },
+            [&](const constant::Scalar<u32>* scalar) {
+                out << scalar->ValueAs<u32>().value << "u";
+            },
+            [&](const constant::Scalar<f32>* scalar) {
+                out << scalar->ValueAs<f32>().value << "f";
+            },
+            [&](const constant::Scalar<f16>* scalar) {
+                out << scalar->ValueAs<f16>().value << "h";
+            },
             [&](const constant::Scalar<bool>* scalar) {
                 out << (scalar->ValueAs<bool>() ? "true" : "false");
             },
             [&](const constant::Splat* splat) {
-                out << splat->Type()->FriendlyName() << "(";
+                out << splat->Type()->FriendlyName() << " ";
                 emit(splat->Index(0));
-                out << ")";
             },
             [&](const constant::Composite* composite) {
-                out << composite->Type()->FriendlyName() << "(";
+                out << composite->Type()->FriendlyName() << " ";
                 for (const auto* elem : composite->elements) {
                     if (elem != composite->elements[0]) {
                         out << ", ";
                     }
                     emit(elem);
                 }
-                out << ")";
             });
     };
     emit(value);
diff --git a/src/tint/ir/constant_test.cc b/src/tint/ir/constant_test.cc
index 1d05db7..43d92b4 100644
--- a/src/tint/ir/constant_test.cc
+++ b/src/tint/ir/constant_test.cc
@@ -32,7 +32,7 @@
     EXPECT_EQ(1.2_f, c->value->As<constant::Scalar<f32>>()->ValueAs<f32>());
 
     c->ToValue(str);
-    EXPECT_EQ("1.20000004768371582031", str.str());
+    EXPECT_EQ("1.20000004768371582031f", str.str());
 
     EXPECT_TRUE(c->value->Is<constant::Scalar<f32>>());
     EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -50,7 +50,7 @@
     EXPECT_EQ(1.1_h, c->value->As<constant::Scalar<f16>>()->ValueAs<f16>());
 
     c->ToValue(str);
-    EXPECT_EQ("1.099609375", str.str());
+    EXPECT_EQ("1.099609375h", str.str());
 
     EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
     EXPECT_TRUE(c->value->Is<constant::Scalar<f16>>());
@@ -68,7 +68,7 @@
     EXPECT_EQ(1_i, c->value->As<constant::Scalar<i32>>()->ValueAs<i32>());
 
     c->ToValue(str);
-    EXPECT_EQ("1", str.str());
+    EXPECT_EQ("1i", str.str());
 
     EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
     EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
@@ -86,7 +86,7 @@
     EXPECT_EQ(2_u, c->value->As<constant::Scalar<u32>>()->ValueAs<u32>());
 
     c->ToValue(str);
-    EXPECT_EQ("2", str.str());
+    EXPECT_EQ("2u", str.str());
 
     EXPECT_FALSE(c->value->Is<constant::Scalar<f32>>());
     EXPECT_FALSE(c->value->Is<constant::Scalar<f16>>());
diff --git a/src/tint/ir/construct.cc b/src/tint/ir/construct.cc
index f71ba40..1507e8f 100644
--- a/src/tint/ir/construct.cc
+++ b/src/tint/ir/construct.cc
@@ -25,12 +25,8 @@
 Construct::~Construct() = default;
 
 utils::StringStream& Construct::ToInstruction(utils::StringStream& out) const {
-    ToValue(out) << " = construct(";
-    if (!Args().IsEmpty()) {
-        out << ", ";
-        EmitArgs(out);
-    }
-    out << ")";
+    ToValue(out) << " = construct ";
+    EmitArgs(out);
     return out;
 }
 
diff --git a/src/tint/ir/convert.cc b/src/tint/ir/convert.cc
index 944b7bc..7ffd6f5 100644
--- a/src/tint/ir/convert.cc
+++ b/src/tint/ir/convert.cc
@@ -28,9 +28,8 @@
 Convert::~Convert() = default;
 
 utils::StringStream& Convert::ToInstruction(utils::StringStream& out) const {
-    ToValue(out) << " = convert(" << from_type_->FriendlyName() << ", ";
+    ToValue(out) << " = convert " << from_type_->FriendlyName() << ", ";
     EmitArgs(out);
-    out << ")";
     return out;
 }
 
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index 54c386a..53bf722 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -89,7 +89,7 @@
     tint::Switch(
         node,
         [&](const ir::Function* f) {
-            Indent() << "%bb" << GetIdForNode(f) << " = Function " << f->name.Name() << std::endl;
+            Indent() << "%fn" << GetIdForNode(f) << " = func " << f->name.Name() << std::endl;
 
             {
                 ScopedIndent func_indent(&indent_size_);
@@ -101,27 +101,28 @@
         [&](const ir::Block* b) {
             // If this block is dead, nothing to do
             if (b->IsDead()) {
-                Indent() << "# Dead" << std::endl;
                 return;
             }
 
-            Indent() << "%bb" << GetIdForNode(b) << " = Block" << std::endl;
+            Indent() << "%fn" << GetIdForNode(b) << " = block" << std::endl;
             EmitBlockInstructions(b);
 
             if (b->branch.target->Is<Terminator>()) {
-                Indent() << "Return";
+                Indent() << "ret";
             } else {
-                Indent() << "BranchTo "
-                         << "%bb" << GetIdForNode(b->branch.target);
+                Indent() << "branch "
+                         << "%fn" << GetIdForNode(b->branch.target);
             }
-            out_ << " (";
-            for (const auto* v : b->branch.args) {
-                if (v != b->branch.args.Front()) {
-                    out_ << ", ";
+            if (!b->branch.args.IsEmpty()) {
+                out_ << " ";
+                for (const auto* v : b->branch.args) {
+                    if (v != b->branch.args.Front()) {
+                        out_ << ", ";
+                    }
+                    v->ToValue(out_);
                 }
-                v->ToValue(out_);
             }
-            out_ << ")" << std::endl;
+            out_ << std::endl;
 
             if (!b->branch.target->Is<Terminator>()) {
                 out_ << std::endl;
@@ -130,15 +131,37 @@
             Walk(b->branch.target);
         },
         [&](const ir::Switch* s) {
-            Indent() << "%bb" << GetIdForNode(s) << " = Switch (";
+            Indent() << "%fn" << GetIdForNode(s) << " = switch ";
             s->condition->ToValue(out_);
-            out_ << ")" << std::endl;
+            out_ << " [";
+            for (const auto& c : s->cases) {
+                if (&c != &s->cases.Front()) {
+                    out_ << ", ";
+                }
+                out_ << "c: (";
+                for (const auto& selector : c.selectors) {
+                    if (&selector != &c.selectors.Front()) {
+                        out_ << " ";
+                    }
+
+                    if (selector.IsDefault()) {
+                        out_ << "default";
+                    } else {
+                        selector.val->ToValue(out_);
+                    }
+                }
+                out_ << ", %fn" << GetIdForNode(c.start.target) << ")";
+            }
+            if (s->merge.target->IsConnected()) {
+                out_ << ", m: %fn" << GetIdForNode(s->merge.target);
+            }
+            out_ << "]" << std::endl;
 
             {
                 ScopedIndent switch_indent(&indent_size_);
                 ScopedStopNode scope(&stop_nodes_, s->merge.target);
                 for (const auto& c : s->cases) {
-                    Indent() << "# Case ";
+                    Indent() << "# case ";
                     for (const auto& selector : c.selectors) {
                         if (&selector != &c.selectors.Front()) {
                             out_ << " ";
@@ -155,13 +178,20 @@
                 }
             }
 
-            Indent() << "# Switch Merge" << std::endl;
-            Walk(s->merge.target);
+            if (s->merge.target->IsConnected()) {
+                Indent() << "# switch merge" << std::endl;
+                Walk(s->merge.target);
+            }
         },
         [&](const ir::If* i) {
-            Indent() << "%bb" << GetIdForNode(i) << " = if (";
+            Indent() << "%fn" << GetIdForNode(i) << " = if ";
             i->condition->ToValue(out_);
-            out_ << ")" << std::endl;
+            out_ << " [t: %fn" << GetIdForNode(i->true_.target) << ", f: %fn"
+                 << GetIdForNode(i->false_.target);
+            if (i->merge.target->IsConnected()) {
+                out_ << ", m: %fn" << GetIdForNode(i->merge.target);
+            }
+            out_ << "]" << std::endl;
 
             {
                 ScopedIndent if_indent(&indent_size_);
@@ -174,13 +204,23 @@
                 Walk(i->false_.target);
             }
 
-            if (!i->merge.target->IsDisconnected()) {
+            if (i->merge.target->IsConnected()) {
                 Indent() << "# if merge" << std::endl;
                 Walk(i->merge.target);
             }
         },
         [&](const ir::Loop* l) {
-            Indent() << "%bb" << GetIdForNode(l) << " = loop" << std::endl;
+            Indent() << "%fn" << GetIdForNode(l) << " = loop [s: %fn"
+                     << GetIdForNode(l->start.target);
+
+            if (l->continuing.target->IsConnected()) {
+                out_ << ", c: %fn" << GetIdForNode(l->continuing.target);
+            }
+            if (l->merge.target->IsConnected()) {
+                out_ << ", m: %fn" << GetIdForNode(l->merge.target);
+            }
+            out_ << "]" << std::endl;
+
             {
                 ScopedStopNode loop_scope(&stop_nodes_, l->merge.target);
                 ScopedIndent loop_indent(&indent_size_);
@@ -190,14 +230,18 @@
                     Walk(l->start.target);
                 }
 
-                Indent() << "# loop continuing" << std::endl;
-                Walk(l->continuing.target);
+                if (l->continuing.target->IsConnected()) {
+                    Indent() << "# loop continuing" << std::endl;
+                    Walk(l->continuing.target);
+                }
             }
 
-            Indent() << "# loop merge" << std::endl;
-            Walk(l->merge.target);
+            if (l->merge.target->IsConnected()) {
+                Indent() << "# loop merge" << std::endl;
+                Walk(l->merge.target);
+            }
         },
-        [&](const ir::Terminator*) { Indent() << "FunctionEnd" << std::endl
+        [&](const ir::Terminator*) { Indent() << "func_end" << std::endl
                                               << std::endl; });
 }
 
diff --git a/src/tint/ir/flow_node.h b/src/tint/ir/flow_node.h
index 2a91674..905f077 100644
--- a/src/tint/ir/flow_node.h
+++ b/src/tint/ir/flow_node.h
@@ -32,8 +32,11 @@
     ///   - Node is a continue target outside control flow (loop that returns)
     utils::Vector<FlowNode*, 2> inbound_branches;
 
-    /// @returns true if this node has no inbound branches
-    bool IsDisconnected() const { return inbound_branches.IsEmpty(); }
+    /// @returns true if this node has inbound branches and branches out
+    bool IsConnected() const { return !IsDead() && !inbound_branches.IsEmpty(); }
+
+    /// @returns true if the node does not branch out
+    virtual bool IsDead() const { return false; }
 
   protected:
     /// Constructor
diff --git a/src/tint/ir/store.cc b/src/tint/ir/store.cc
index 2680a2a..8d35214 100644
--- a/src/tint/ir/store.cc
+++ b/src/tint/ir/store.cc
@@ -29,9 +29,9 @@
 Store::~Store() = default;
 
 utils::StringStream& Store::ToInstruction(utils::StringStream& out) const {
-    out << "store(";
+    out << "store ";
     to_->ToValue(out) << ", ";
-    from_->ToValue(out) << ")";
+    from_->ToValue(out);
     return out;
 }
 
diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc
index d67e6d6..82347dc 100644
--- a/src/tint/ir/store_test.cc
+++ b/src/tint/ir/store_test.cc
@@ -41,7 +41,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "store(%0, 4)");
+    EXPECT_EQ(str.str(), "store %0, 4i");
 }
 
 TEST_F(IR_InstructionTest, Store_Usage) {
diff --git a/src/tint/ir/unary.cc b/src/tint/ir/unary.cc
index 9eb1509..f3c4f24 100644
--- a/src/tint/ir/unary.cc
+++ b/src/tint/ir/unary.cc
@@ -31,21 +31,22 @@
     ToValue(out) << " = ";
     switch (GetKind()) {
         case Unary::Kind::kAddressOf:
-            out << "&";
+            out << "addr_of";
             break;
         case Unary::Kind::kComplement:
-            out << "~";
+            out << "bit_complement";
             break;
         case Unary::Kind::kIndirection:
-            out << "*";
+            out << "indirection";
             break;
         case Unary::Kind::kNegation:
-            out << "-";
+            out << "negation";
             break;
         case Unary::Kind::kNot:
-            out << "!";
+            out << "log_not";
             break;
     }
+    out << " ";
     val_->ToValue(out);
     return out;
 }
diff --git a/src/tint/ir/unary_test.cc b/src/tint/ir/unary_test.cc
index ada6103..ff247a2 100644
--- a/src/tint/ir/unary_test.cc
+++ b/src/tint/ir/unary_test.cc
@@ -45,7 +45,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = &4");
+    EXPECT_EQ(str.str(), "%1(ptr<private, i32, read_write>) = addr_of 4i");
 }
 
 TEST_F(IR_InstructionTest, CreateComplement) {
@@ -63,7 +63,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = ~4");
+    EXPECT_EQ(str.str(), "%1(i32) = bit_complement 4i");
 }
 
 TEST_F(IR_InstructionTest, CreateIndirection) {
@@ -83,7 +83,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = *4");
+    EXPECT_EQ(str.str(), "%1(i32) = indirection 4i");
 }
 
 TEST_F(IR_InstructionTest, CreateNegation) {
@@ -101,7 +101,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(i32) = -4");
+    EXPECT_EQ(str.str(), "%1(i32) = negation 4i");
 }
 
 TEST_F(IR_InstructionTest, CreateNot) {
@@ -119,7 +119,7 @@
 
     utils::StringStream str;
     inst->ToInstruction(str);
-    EXPECT_EQ(str.str(), "%1(bool) = !true");
+    EXPECT_EQ(str.str(), "%1(bool) = log_not true");
 }
 
 TEST_F(IR_InstructionTest, Unary_Usage) {
diff --git a/src/tint/ir/user_call.cc b/src/tint/ir/user_call.cc
index bd58d70..f23a2ca 100644
--- a/src/tint/ir/user_call.cc
+++ b/src/tint/ir/user_call.cc
@@ -25,9 +25,11 @@
 UserCall::~UserCall() = default;
 
 utils::StringStream& UserCall::ToInstruction(utils::StringStream& out) const {
-    ToValue(out) << " = call(" << name_.Name() << ", ";
+    ToValue(out) << " = call " << name_.Name();
+    if (Args().Length() > 0) {
+        out << ", ";
+    }
     EmitArgs(out);
-    out << ")";
     return out;
 }