[ir] Convert tests to block builder.

This CL updates the tests to use the new builder interface which allows
setting the current block and auto-appending.

Bug: tint:1718
Change-Id: Ic655cbc465d7ec4fe45a109ce53f46c1c13ed7d9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/137208
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/ir/block.cc b/src/tint/ir/block.cc
index 4dad6c2..c743065 100644
--- a/src/tint/ir/block.cc
+++ b/src/tint/ir/block.cc
@@ -157,16 +157,4 @@
     inst->next = nullptr;
 }
 
-void Block::SetInstructions(utils::VectorRef<Instruction*> instructions) {
-    for (auto* i : instructions) {
-        Append(i);
-    }
-}
-
-void Block::SetInstructions(std::initializer_list<Instruction*> instructions) {
-    for (auto* i : instructions) {
-        Append(i);
-    }
-}
-
 }  // namespace tint::ir
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index 9b9a4ca..60f6b31 100644
--- a/src/tint/ir/block.h
+++ b/src/tint/ir/block.h
@@ -50,14 +50,6 @@
         return instructions_.last->As<ir::Branch>();
     }
 
-    /// Sets the instructions in the block
-    /// @param instructions the instructions to set
-    void SetInstructions(utils::VectorRef<Instruction*> instructions);
-
-    /// Sets the instructions in the block
-    /// @param instructions the instructions to set
-    void SetInstructions(std::initializer_list<Instruction*> instructions);
-
     /// @returns the instructions in the block
     Instruction* Instructions() { return instructions_.first; }
 
diff --git a/src/tint/ir/block_test.cc b/src/tint/ir/block_test.cc
index 3549a05..e9523c5 100644
--- a/src/tint/ir/block_test.cc
+++ b/src/tint/ir/block_test.cc
@@ -83,35 +83,6 @@
     EXPECT_TRUE(blk->HasBranchTarget());
 }
 
-TEST_F(IR_BlockTest, SetInstructions) {
-    auto* inst1 = b.Loop();
-    auto* inst2 = b.Loop();
-    auto* inst3 = b.Loop();
-
-    auto* blk = b.Block();
-    blk->SetInstructions({inst1, inst2, inst3});
-
-    ASSERT_EQ(inst1->Block(), blk);
-    ASSERT_EQ(inst2->Block(), blk);
-    ASSERT_EQ(inst3->Block(), blk);
-
-    EXPECT_FALSE(blk->IsEmpty());
-    EXPECT_EQ(3u, blk->Length());
-
-    auto* inst = blk->Instructions();
-    ASSERT_EQ(inst, inst1);
-    ASSERT_EQ(inst->prev, nullptr);
-    inst = inst->next;
-
-    ASSERT_EQ(inst, inst2);
-    ASSERT_EQ(inst->prev, inst1);
-    inst = inst->next;
-
-    ASSERT_EQ(inst, inst3);
-    ASSERT_EQ(inst->prev, inst2);
-    ASSERT_EQ(inst->next, nullptr);
-}
-
 TEST_F(IR_BlockTest, Append) {
     auto* inst1 = b.Loop();
     auto* inst2 = b.Loop();
@@ -285,13 +256,12 @@
 }
 
 TEST_F(IR_BlockTest, Replace_Middle) {
-    auto* inst1 = b.Loop();
-    auto* inst2 = b.Loop();
-    auto* inst3 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst1, inst4, inst3});
+    auto* inst1 = blk->Append(b.Loop());
+    auto* inst4 = blk->Append(b.Loop());
+    auto* inst3 = blk->Append(b.Loop());
+
+    auto* inst2 = b.Loop();
     blk->Replace(inst4, inst2);
 
     ASSERT_EQ(inst1->Block(), blk);
@@ -317,12 +287,11 @@
 }
 
 TEST_F(IR_BlockTest, Replace_Start) {
-    auto* inst1 = b.Loop();
-    auto* inst2 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst4, inst2});
+    auto* inst4 = blk->Append(b.Loop());
+    auto* inst2 = blk->Append(b.Loop());
+
+    auto* inst1 = b.Loop();
     blk->Replace(inst4, inst1);
 
     ASSERT_EQ(inst1->Block(), blk);
@@ -343,12 +312,11 @@
 }
 
 TEST_F(IR_BlockTest, Replace_End) {
-    auto* inst1 = b.Loop();
-    auto* inst2 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst1, inst4});
+    auto* inst1 = blk->Append(b.Loop());
+    auto* inst4 = blk->Append(b.Loop());
+
+    auto* inst2 = b.Loop();
     blk->Replace(inst4, inst2);
 
     ASSERT_EQ(inst1->Block(), blk);
@@ -369,11 +337,10 @@
 }
 
 TEST_F(IR_BlockTest, Replace_OnlyNode) {
-    auto* inst1 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst4});
+    auto* inst4 = blk->Append(b.Loop());
+
+    auto* inst1 = b.Loop();
     blk->Replace(inst4, inst1);
 
     ASSERT_EQ(inst1->Block(), blk);
@@ -389,12 +356,10 @@
 }
 
 TEST_F(IR_BlockTest, Remove_Middle) {
-    auto* inst1 = b.Loop();
-    auto* inst2 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst1, inst4, inst2});
+    auto* inst1 = blk->Append(b.Loop());
+    auto* inst4 = blk->Append(b.Loop());
+    auto* inst2 = blk->Append(b.Loop());
     blk->Remove(inst4);
 
     ASSERT_EQ(inst4->Block(), nullptr);
@@ -413,11 +378,9 @@
 }
 
 TEST_F(IR_BlockTest, Remove_Start) {
-    auto* inst1 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst4, inst1});
+    auto* inst4 = blk->Append(b.Loop());
+    auto* inst1 = blk->Append(b.Loop());
     blk->Remove(inst4);
 
     ASSERT_EQ(inst4->Block(), nullptr);
@@ -432,11 +395,9 @@
 }
 
 TEST_F(IR_BlockTest, Remove_End) {
-    auto* inst1 = b.Loop();
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst1, inst4});
+    auto* inst1 = blk->Append(b.Loop());
+    auto* inst4 = blk->Append(b.Loop());
     blk->Remove(inst4);
 
     ASSERT_EQ(inst4->Block(), nullptr);
@@ -451,10 +412,8 @@
 }
 
 TEST_F(IR_BlockTest, Remove_OnlyNode) {
-    auto* inst4 = b.Loop();
-
     auto* blk = b.Block();
-    blk->SetInstructions({inst4});
+    auto* inst4 = blk->Append(b.Loop());
     blk->Remove(inst4);
 
     ASSERT_EQ(inst4->Block(), nullptr);
diff --git a/src/tint/ir/transform/add_empty_entry_point.cc b/src/tint/ir/transform/add_empty_entry_point.cc
index 7a5506d..3c28e59 100644
--- a/src/tint/ir/transform/add_empty_entry_point.cc
+++ b/src/tint/ir/transform/add_empty_entry_point.cc
@@ -37,7 +37,7 @@
     ir::Builder builder(*ir);
     auto* ep = builder.Function("unused_entry_point", ir->Types().void_(),
                                 Function::PipelineStage::kCompute, std::array{1u, 1u, 1u});
-    ep->StartTarget()->SetInstructions({builder.Return(ep)});
+    ep->StartTarget()->Append(builder.Return(ep));
     ir->functions.Push(ep);
 }
 
diff --git a/src/tint/ir/transform/add_empty_entry_point_test.cc b/src/tint/ir/transform/add_empty_entry_point_test.cc
index 558e2af..c5c60a1 100644
--- a/src/tint/ir/transform/add_empty_entry_point_test.cc
+++ b/src/tint/ir/transform/add_empty_entry_point_test.cc
@@ -39,7 +39,7 @@
 
 TEST_F(IR_AddEmptyEntryPointTest, ExistingEntryPoint) {
     auto* ep = b.Function("main", mod.Types().void_(), Function::PipelineStage::kFragment);
-    ep->StartTarget()->SetInstructions({b.Return(ep)});
+    ep->StartTarget()->Append(b.Return(ep));
     mod.functions.Push(ep);
 
     auto* expect = R"(
diff --git a/src/tint/ir/validate_test.cc b/src/tint/ir/validate_test.cc
index d2f07d0..d49b0dd 100644
--- a/src/tint/ir/validate_test.cc
+++ b/src/tint/ir/validate_test.cc
@@ -73,7 +73,8 @@
     mod.functions.Push(f);
 
     f->SetParams({b.FunctionParam(ty.i32()), b.FunctionParam(ty.f32())});
-    f->StartTarget()->SetInstructions({b.Return(f)});
+    f->StartTarget()->Append(b.Return(f));
+
     auto res = ir::Validate(mod);
     EXPECT_TRUE(res) << res.Failure().str();
 }
@@ -102,8 +103,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.f32(), obj, 1_u, 0_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.f32(), obj, 1_u, 0_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     EXPECT_TRUE(res) << res.Failure().str();
@@ -116,8 +118,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.ptr<private_, f32>(), obj, 1_u, 0_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.ptr<private_, f32>(), obj, 1_u, 0_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     EXPECT_TRUE(res) << res.Failure().str();
@@ -129,8 +132,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.f32(), obj, -1_i));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.f32(), obj, -1_i);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -158,8 +162,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.f32(), obj, 1_u, 3_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.f32(), obj, 1_u, 3_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -192,8 +197,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.ptr<private_, f32>(), obj, 1_u, 3_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.ptr<private_, f32>(), obj, 1_u, 3_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -226,8 +232,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.f32(), obj, 1_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.f32(), obj, 1_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -255,8 +262,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.ptr<private_, f32>(), obj, 1_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.ptr<private_, f32>(), obj, 1_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -293,8 +301,9 @@
     f->SetParams({obj, idx});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.i32(), obj, idx));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.i32(), obj, idx);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -338,8 +347,9 @@
     f->SetParams({obj, idx});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.i32(), obj, idx));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.i32(), obj, idx);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -373,8 +383,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.i32(), obj, 1_u, 1_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.i32(), obj, 1_u, 1_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -404,8 +415,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.ptr<private_, i32>(), obj, 1_u, 1_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.ptr<private_, i32>(), obj, 1_u, 1_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -436,8 +448,9 @@
     f->SetParams({obj});
     mod.functions.Push(f);
 
-    f->StartTarget()->Append(b.Access(ty.f32(), obj, 1_u, 1_u));
-    f->StartTarget()->Append(b.Return(f));
+    auto sb = b.With(f->StartTarget());
+    sb.Access(ty.f32(), obj, 1_u, 1_u);
+    sb.Return(f);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
@@ -465,7 +478,10 @@
     auto* f = b.Function("my_func", ty.void_());
     mod.functions.Push(f);
 
-    f->StartTarget()->SetInstructions({b.Return(f), b.Return(f)});
+    auto sb = b.With(f->StartTarget());
+    sb.Return(f);
+    sb.Return(f);
+
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(res.Failure().str(), R"(:3:5 error: block: branch which isn't the final instruction
diff --git a/src/tint/transform/manager_test.cc b/src/tint/transform/manager_test.cc
index a41fa87..c1083b2 100644
--- a/src/tint/transform/manager_test.cc
+++ b/src/tint/transform/manager_test.cc
@@ -51,7 +51,7 @@
     void Run(ir::Module* mod, const DataMap&, DataMap&) const override {
         ir::Builder builder(*mod);
         auto* func = builder.Function("ir_func", mod->Types().Get<type::Void>());
-        func->StartTarget()->SetInstructions(utils::Vector{builder.Return(func)});
+        func->StartTarget()->Append(builder.Return(func));
         mod->functions.Push(func);
     }
 };
@@ -68,7 +68,7 @@
     ir::Module mod;
     ir::Builder builder(mod);
     auto* func = builder.Function("main", mod.Types().Get<type::Void>());
-    func->StartTarget()->SetInstructions(utils::Vector{builder.Return(func)});
+    func->StartTarget()->Append(builder.Return(func));
     builder.ir.functions.Push(func);
     return mod;
 }
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
index 4818c00..fa5c977 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
@@ -28,10 +28,12 @@
 
 TEST_F(SpvGeneratorImplTest_Access, Array_Value_ConstantIndex) {
     auto* arr_val = b.FunctionParam(ty.array(ty.i32(), 4));
-    auto* access = b.Access(ty.i32(), arr_val, 1_u);
     auto* func = b.Function("foo", ty.void_());
     func->SetParams({arr_val});
-    func->StartTarget()->SetInstructions({access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    sb.Access(ty.i32(), arr_val, 1_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -54,10 +56,12 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Array_Pointer_ConstantIndex) {
-    auto* arr_var = b.Var(ptr(ty.array(ty.i32(), 4)));
-    auto* access = b.Access(ptr(ty.i32()), arr_var, 1_u);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({arr_var, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* arr_var = sb.Var(ptr(ty.array(ty.i32(), 4)));
+    sb.Access(ptr(ty.i32()), arr_var, 1_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -83,13 +87,14 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Array_Pointer_DynamicIndex) {
-    auto* arr_var = b.Var(ptr(ty.array(ty.i32(), 4)));
-    auto* idx_var = b.Var(ptr(ty.i32()));
-    auto* idx = b.Load(idx_var);
-    auto* access = b.Access(ptr(ty.i32()), arr_var, idx);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{idx_var, idx, arr_var, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx = sb.Load(idx_var);
+    auto* arr_var = sb.Var(ptr(ty.array(ty.i32(), 4)));
+    sb.Access(ptr(ty.i32()), arr_var, idx);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -145,11 +150,13 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Matrix_Pointer_ConstantIndex) {
-    auto* mat_var = b.Var(ptr(ty.mat2x2(ty.f32())));
-    auto* access_vec = b.Access(ptr(ty.vec2(ty.f32())), mat_var, 1_u);
-    auto* access_el = b.Access(ptr(ty.f32()), mat_var, 1_u, 0_u);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({access_vec, access_el, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* mat_var = sb.Var(ptr(ty.mat2x2(ty.f32())));
+    sb.Access(ptr(ty.vec2(ty.f32())), mat_var, 1_u);
+    sb.Access(ptr(ty.f32()), mat_var, 1_u, 0_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -157,31 +164,35 @@
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
 %2 = OpTypeVoid
 %3 = OpTypeFunction %2
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 2
+%9 = OpTypeFloat 32
+%8 = OpTypeVector %9 2
+%7 = OpTypeMatrix %8 2
 %6 = OpTypePointer Function %7
-%11 = OpTypeInt 32 0
-%10 = OpConstant %11 1
-%13 = OpTypePointer Function %8
-%14 = OpConstant %11 0
+%11 = OpTypePointer Function %8
+%13 = OpTypeInt 32 0
+%12 = OpConstant %13 1
+%15 = OpTypePointer Function %9
+%16 = OpConstant %13 0
 %1 = OpFunction %2 None %3
 %4 = OpLabel
-%5 = OpAccessChain %6 %9 %10
-%12 = OpAccessChain %13 %9 %10 %14
+%5 = OpVariable %6 Function
+%10 = OpAccessChain %11 %5 %12
+%14 = OpAccessChain %15 %5 %12 %16
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Matrix_Pointer_DynamicIndex) {
-    auto* mat_var = b.Var(ptr(ty.mat2x2(ty.f32())));
-    auto* idx_var = b.Var(ptr(ty.i32()));
-    auto* idx = b.Load(idx_var);
-    auto* access_vec = b.Access(ptr(ty.vec2(ty.f32())), mat_var, idx);
-    auto* access_el = b.Access(ptr(ty.f32()), mat_var, idx, idx);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{idx_var, idx, mat_var, access_vec, access_el, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx = sb.Load(idx_var);
+    auto* mat_var = sb.Var(ptr(ty.mat2x2(ty.f32())));
+    sb.Access(ptr(ty.vec2(ty.f32())), mat_var, idx);
+    sb.Access(ptr(ty.f32()), mat_var, idx, idx);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -210,11 +221,13 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Vector_Value_ConstantIndex) {
-    auto* vec_val = b.FunctionParam(ty.vec4(ty.i32()));
-    auto* access = b.Access(ty.i32(), vec_val, 1_u);
     auto* func = b.Function("foo", ty.void_());
+    auto* vec_val = b.FunctionParam(ty.vec4(ty.i32()));
     func->SetParams({vec_val});
-    func->StartTarget()->SetInstructions({access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    sb.Access(ty.i32(), vec_val, 1_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -234,13 +247,15 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Vector_Value_DynamicIndex) {
-    auto* vec_val = b.FunctionParam(ty.vec4(ty.i32()));
-    auto* idx_var = b.Var(ptr(ty.i32()));
-    auto* idx = b.Load(idx_var);
-    auto* access = b.Access(ty.i32(), vec_val, idx);
     auto* func = b.Function("foo", ty.void_());
+    auto* vec_val = b.FunctionParam(ty.vec4(ty.i32()));
     func->SetParams({vec_val});
-    func->StartTarget()->SetInstructions({idx_var, idx, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx = sb.Load(idx_var);
+    sb.Access(ty.i32(), vec_val, idx);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -263,10 +278,12 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Vector_Pointer_ConstantIndex) {
-    auto* vec_var = b.Var(ptr(ty.vec4(ty.i32())));
-    auto* access = b.Access(ptr(ty.i32()), vec_var, 1_u);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({vec_var, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* vec_var = sb.Var(ptr(ty.vec4(ty.i32())));
+    sb.Access(ptr(ty.i32()), vec_var, 1_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -290,13 +307,14 @@
 }
 
 TEST_F(SpvGeneratorImplTest_Access, Vector_Pointer_DynamicIndex) {
-    auto* vec_var = b.Var(ptr(ty.vec4(ty.i32())));
-    auto* idx_var = b.Var(ptr(ty.i32()));
-    auto* idx = b.Load(idx_var);
-    auto* access = b.Access(ptr(ty.i32()), vec_var, idx);
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{idx_var, idx, vec_var, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx = sb.Load(idx_var);
+    auto* vec_var = sb.Var(ptr(ty.vec4(ty.i32())));
+    sb.Access(ptr(ty.i32()), vec_var, idx);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -321,12 +339,14 @@
 
 TEST_F(SpvGeneratorImplTest_Access, NestedVector_Value_DynamicIndex) {
     auto* val = b.FunctionParam(ty.array(ty.array(ty.vec4(ty.i32()), 4), 4));
-    auto* idx_var = b.Var(ptr(ty.i32()));
-    auto* idx = b.Load(idx_var);
-    auto* access = b.Access(ty.i32(), val, 1_u, 2_u, idx);
     auto* func = b.Function("foo", ty.void_());
     func->SetParams({val});
-    func->StartTarget()->SetInstructions({idx_var, idx, access, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx = sb.Load(idx_var);
+    sb.Access(ty.i32(), val, 1_u, 2_u, idx);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -366,11 +386,13 @@
         },
         16u, 32u, 32u);
     auto* str_val = b.FunctionParam(str);
-    auto* access_vec = b.Access(ty.i32(), str_val, 1_u);
-    auto* access_el = b.Access(ty.i32(), str_val, 1_u, 2_u);
     auto* func = b.Function("foo", ty.void_());
     func->SetParams({str_val});
-    func->StartTarget()->SetInstructions({access_vec, access_el, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    sb.Access(ty.i32(), str_val, 1_u);
+    sb.Access(ty.i32(), str_val, 1_u, 2_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -407,12 +429,14 @@
                                        16u, type::StructMemberAttributes{}),
         },
         16u, 32u, 32u);
-    auto* str_var = b.Var(ptr(str));
-    auto* access_vec = b.Access(ptr(ty.i32()), str_var, 1_u);
-    auto* access_el = b.Access(ptr(ty.i32()), str_var, 1_u, 2_u);
+
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{str_var, access_vec, access_el, b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* str_var = sb.Var(ptr(str));
+    sb.Access(ptr(ty.i32()), str_var, 1_u);
+    sb.Access(ptr(ty.i32()), str_var, 1_u, 2_u);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
index 6ca13f7..37b702c 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_binary_test.cc
@@ -37,10 +37,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, MakeScalarType(params.type),
-                               MakeScalarValue(params.type), MakeScalarValue(params.type)),
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, MakeScalarType(params.type), MakeScalarValue(params.type),
+              MakeScalarValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -51,11 +51,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, MakeVectorType(params.type),
-                               MakeVectorValue(params.type), MakeVectorValue(params.type)),
-
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, MakeVectorType(params.type), MakeVectorValue(params.type),
+              MakeVectorValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -88,10 +87,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, MakeScalarType(params.type),
-                               MakeScalarValue(params.type), MakeScalarValue(params.type)),
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, MakeScalarType(params.type), MakeScalarValue(params.type),
+              MakeScalarValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -102,11 +101,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, MakeVectorType(params.type),
-                               MakeVectorValue(params.type), MakeVectorValue(params.type)),
-
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, MakeVectorType(params.type), MakeVectorValue(params.type),
+              MakeVectorValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -131,25 +129,24 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, ty.bool_(), MakeScalarValue(params.type),
-                               MakeScalarValue(params.type)),
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, ty.bool_(), MakeScalarValue(params.type), MakeScalarValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
     generator_.EmitFunction(func);
     EXPECT_THAT(DumpModule(generator_.Module()), ::testing::HasSubstr(params.spirv_inst));
 }
+
 TEST_P(Comparison, Vector) {
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions(
-        utils::Vector{b.Binary(params.kind, ty.vec2(ty.bool_()), MakeVectorValue(params.type),
-                               MakeVectorValue(params.type)),
-
-                      b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Binary(params.kind, ty.vec2(ty.bool_()), MakeVectorValue(params.type),
+              MakeVectorValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -204,8 +201,11 @@
 
 TEST_F(SpvGeneratorImplTest, Binary_Chain) {
     auto* func = b.Function("foo", ty.void_());
-    auto* a = b.Subtract(ty.i32(), 1_i, 2_i);
-    func->StartTarget()->SetInstructions({a, b.Add(ty.i32(), a, a), b.Return(func)});
+
+    auto sb = b.With(func->StartTarget());
+    auto* a = sb.Subtract(ty.i32(), 1_i, 2_i);
+    sb.Add(ty.i32(), a, a);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_builtin_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_builtin_test.cc
index 44d0505..ae45e1c 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_builtin_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_builtin_test.cc
@@ -38,10 +38,9 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({
-        b.Call(MakeScalarType(params.type), params.function, MakeScalarValue(params.type)),
-        b.Return(func),
-    });
+    auto sb = b.With(func->StartTarget());
+    sb.Call(MakeScalarType(params.type), params.function, MakeScalarValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -52,10 +51,9 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({
-        b.Call(MakeVectorType(params.type), params.function, MakeVectorValue(params.type)),
-        b.Return(func),
-    });
+    auto sb = b.With(func->StartTarget());
+    sb.Call(MakeVectorType(params.type), params.function, MakeVectorValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -69,12 +67,10 @@
 
 // Test that abs of an unsigned value just folds away.
 TEST_F(SpvGeneratorImplTest, Builtin_Abs_u32) {
-    auto* result = b.Call(MakeScalarType(kU32), builtin::Function::kAbs, MakeScalarValue(kU32));
     auto* func = b.Function("foo", MakeScalarType(kU32));
-    func->StartTarget()->SetInstructions({
-        result,
-        b.Return(func, result),
-    });
+    auto sb = b.With(func->StartTarget());
+    auto* result = sb.Call(MakeScalarType(kU32), builtin::Function::kAbs, MakeScalarValue(kU32));
+    sb.Return(func, result);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -91,12 +87,10 @@
 }
 
 TEST_F(SpvGeneratorImplTest, Builtin_Abs_vec2u) {
-    auto* result = b.Call(MakeVectorType(kU32), builtin::Function::kAbs, MakeVectorValue(kU32));
     auto* func = b.Function("foo", MakeVectorType(kU32));
-    func->StartTarget()->SetInstructions({
-        result,
-        b.Return(func, result),
-    });
+    auto sb = b.With(func->StartTarget());
+    auto* result = sb.Call(MakeVectorType(kU32), builtin::Function::kAbs, MakeVectorValue(kU32));
+    sb.Return(func, result);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -121,11 +115,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({
-        b.Call(MakeScalarType(params.type), params.function, MakeScalarValue(params.type),
-               MakeScalarValue(params.type)),
-        b.Return(func),
-    });
+    auto sb = b.With(func->StartTarget());
+    sb.Call(MakeScalarType(params.type), params.function, MakeScalarValue(params.type),
+            MakeScalarValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -136,12 +129,10 @@
     auto params = GetParam();
 
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({
-        b.Call(MakeVectorType(params.type), params.function, MakeVectorValue(params.type),
-               MakeVectorValue(params.type)),
-
-        b.Return(func),
-    });
+    auto sb = b.With(func->StartTarget());
+    sb.Call(MakeVectorType(params.type), params.function, MakeVectorValue(params.type),
+            MakeVectorValue(params.type));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
index 9c67418..81f1091 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_function_test.cc
@@ -19,7 +19,7 @@
 
 TEST_F(SpvGeneratorImplTest, Function_Empty) {
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({b.Return(func)});
+    func->StartTarget()->Append(b.Return(func));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -37,7 +37,7 @@
 // Test that we do not emit the same function type more than once.
 TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
     auto* func = b.Function("foo", ty.void_());
-    func->StartTarget()->SetInstructions({b.Return(func)});
+    func->StartTarget()->Append(b.Return(func));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -52,7 +52,7 @@
 TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Compute) {
     auto* func =
         b.Function("main", ty.void_(), ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
-    func->StartTarget()->SetInstructions({b.Return(func)});
+    func->StartTarget()->Append(b.Return(func));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -71,7 +71,7 @@
 
 TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Fragment) {
     auto* func = b.Function("main", ty.void_(), ir::Function::PipelineStage::kFragment);
-    func->StartTarget()->SetInstructions({b.Return(func)});
+    func->StartTarget()->Append(b.Return(func));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -90,7 +90,7 @@
 
 TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Vertex) {
     auto* func = b.Function("main", ty.void_(), ir::Function::PipelineStage::kVertex);
-    func->StartTarget()->SetInstructions({b.Return(func)});
+    func->StartTarget()->Append(b.Return(func));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -108,13 +108,13 @@
 
 TEST_F(SpvGeneratorImplTest, Function_EntryPoint_Multiple) {
     auto* f1 = b.Function("main1", ty.void_(), ir::Function::PipelineStage::kCompute, {{32, 4, 1}});
-    f1->StartTarget()->SetInstructions({b.Return(f1)});
+    f1->StartTarget()->Append(b.Return(f1));
 
     auto* f2 = b.Function("main2", ty.void_(), ir::Function::PipelineStage::kCompute, {{8, 2, 16}});
-    f2->StartTarget()->SetInstructions({b.Return(f2)});
+    f2->StartTarget()->Append(b.Return(f2));
 
     auto* f3 = b.Function("main3", ty.void_(), ir::Function::PipelineStage::kFragment);
-    f3->StartTarget()->SetInstructions({b.Return(f3)});
+    f3->StartTarget()->Append(b.Return(f3));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -149,7 +149,7 @@
 
 TEST_F(SpvGeneratorImplTest, Function_ReturnValue) {
     auto* func = b.Function("foo", ty.i32());
-    func->StartTarget()->SetInstructions({b.Return(func, i32(42))});
+    func->StartTarget()->Append(b.Return(func, i32(42)));
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -169,13 +169,15 @@
     auto* i32 = ty.i32();
     auto* x = b.FunctionParam(i32);
     auto* y = b.FunctionParam(i32);
-    auto* result = b.Add(i32, x, y);
     auto* func = b.Function("foo", i32);
     func->SetParams({x, y});
-    func->StartTarget()->SetInstructions({result, b.Return(func, result)});
     mod.SetName(x, "x");
     mod.SetName(y, "y");
 
+    auto sb = b.With(func->StartTarget());
+    auto* result = sb.Add(i32, x, y);
+    sb.Return(func, result);
+
     ASSERT_TRUE(IRIsValid()) << Error();
 
     generator_.EmitFunction(func);
@@ -198,14 +200,21 @@
     auto* i32_ty = ty.i32();
     auto* x = b.FunctionParam(i32_ty);
     auto* y = b.FunctionParam(i32_ty);
-    auto* result = b.Add(i32_ty, x, y);
     auto* foo = b.Function("foo", i32_ty);
     foo->SetParams({x, y});
-    foo->StartTarget()->SetInstructions({result, b.Return(foo, result)});
+
+    {
+        auto sb = b.With(foo->StartTarget());
+        auto* result = sb.Add(i32_ty, x, y);
+        sb.Return(foo, result);
+    }
 
     auto* bar = b.Function("bar", ty.void_());
-    bar->StartTarget()->SetInstructions(
-        utils::Vector{b.Call(i32_ty, foo, i32(2), i32(3)), b.Return(bar)});
+    {
+        auto sb = b.With(bar->StartTarget());
+        sb.Call(i32_ty, foo, i32(2), i32(3));
+        sb.Return(bar);
+    }
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -236,11 +245,12 @@
 
 TEST_F(SpvGeneratorImplTest, Function_Call_Void) {
     auto* foo = b.Function("foo", ty.void_());
-    foo->StartTarget()->SetInstructions({b.Return(foo)});
+    foo->StartTarget()->Append(b.Return(foo));
 
     auto* bar = b.Function("bar", ty.void_());
-    bar->StartTarget()->SetInstructions(
-        utils::Vector{b.Call(ty.void_(), foo, utils::Empty), b.Return(bar)});
+    auto sb = b.With(bar->StartTarget());
+    sb.Call(ty.void_(), foo, utils::Empty);
+    sb.Return(bar);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
index 6534a56..80b98c0 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_if_test.cc
@@ -23,11 +23,11 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.ExitIf(i)});
-    i->False()->SetInstructions({b.ExitIf(i)});
-    i->Merge()->SetInstructions({b.Return(func)});
+    i->True()->Append(b.ExitIf(i));
+    i->False()->Append(b.ExitIf(i));
+    i->Merge()->Append(b.Return(func));
 
-    func->StartTarget()->SetInstructions({i});
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -51,13 +51,14 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* i = b.If(true);
-    i->False()->SetInstructions({b.ExitIf(i)});
-    i->Merge()->SetInstructions({b.Return(func)});
+    i->False()->Append(b.ExitIf(i));
+    i->Merge()->Append(b.Return(func));
 
-    auto* true_block = i->True();
-    true_block->SetInstructions({b.Add(ty.i32(), 1_i, 1_i), b.ExitIf(i)});
+    auto tb = b.With(i->True());
+    tb.Add(ty.i32(), 1_i, 1_i);
+    tb.ExitIf(i);
 
-    func->StartTarget()->SetInstructions({i});
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -86,13 +87,14 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.ExitIf(i)});
-    i->Merge()->SetInstructions({b.Return(func)});
+    i->True()->Append(b.ExitIf(i));
+    i->Merge()->Append(b.Return(func));
 
-    auto* false_block = i->False();
-    false_block->SetInstructions({b.Add(ty.i32(), 1_i, 1_i), b.ExitIf(i)});
+    auto fb = b.With(i->False());
+    fb.Add(ty.i32(), 1_i, 1_i);
+    fb.ExitIf(i);
 
-    func->StartTarget()->SetInstructions({i});
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -121,10 +123,10 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.Return(func)});
-    i->False()->SetInstructions({b.Return(func)});
+    i->True()->Append(b.Return(func));
+    i->False()->Append(b.Return(func));
 
-    func->StartTarget()->SetInstructions({i});
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -154,12 +156,13 @@
     auto* merge_param = b.BlockParam(b.ir.Types().i32());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.ExitIf(i, 10_i)});
-    i->False()->SetInstructions({b.ExitIf(i, 20_i)});
-    i->Merge()->SetParams({merge_param});
-    i->Merge()->SetInstructions({b.Return(func, merge_param)});
+    i->True()->Append(b.ExitIf(i, 10_i));
+    i->False()->Append(b.ExitIf(i, 20_i));
 
-    func->StartTarget()->SetInstructions({i});
+    i->Merge()->SetParams({merge_param});
+    i->Merge()->Append(b.Return(func, merge_param));
+
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -193,12 +196,13 @@
     auto* merge_param = b.BlockParam(b.ir.Types().i32());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.Return(func, 42_i)});
-    i->False()->SetInstructions({b.ExitIf(i, 20_i)});
-    i->Merge()->SetParams({merge_param});
-    i->Merge()->SetInstructions({b.Return(func, merge_param)});
+    i->True()->Append(b.Return(func, 42_i));
+    i->False()->Append(b.ExitIf(i, 20_i));
 
-    func->StartTarget()->SetInstructions({i});
+    i->Merge()->SetParams({merge_param});
+    i->Merge()->Append(b.Return(func, merge_param));
+
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -232,12 +236,13 @@
     auto* merge_param = b.BlockParam(b.ir.Types().i32());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.ExitIf(i, 10_i)});
-    i->False()->SetInstructions({b.Return(func, 42_i)});
-    i->Merge()->SetParams({merge_param});
-    i->Merge()->SetInstructions({b.Return(func, merge_param)});
+    i->True()->Append(b.ExitIf(i, 10_i));
+    i->False()->Append(b.Return(func, 42_i));
 
-    func->StartTarget()->SetInstructions({i});
+    i->Merge()->SetParams({merge_param});
+    i->Merge()->Append(b.Return(func, merge_param));
+
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -272,12 +277,13 @@
     auto* merge_param_1 = b.BlockParam(b.ir.Types().bool_());
 
     auto* i = b.If(true);
-    i->True()->SetInstructions({b.ExitIf(i, 10_i, true)});
-    i->False()->SetInstructions({b.ExitIf(i, 20_i, false)});
-    i->Merge()->SetParams({merge_param_0, merge_param_1});
-    i->Merge()->SetInstructions({b.Return(func, merge_param_0)});
+    i->True()->Append(b.ExitIf(i, 10_i, true));
+    i->False()->Append(b.ExitIf(i, 20_i, false));
 
-    func->StartTarget()->SetInstructions({i});
+    i->Merge()->SetParams({merge_param_0, merge_param_1});
+    i->Merge()->Append(b.Return(func, merge_param_0));
+
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_loop_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_loop_test.cc
index c1e3f00..deae6e3 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_loop_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_loop_test.cc
@@ -183,7 +183,6 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* loop = b.Loop();
-
     loop->Body()->Append(b.Return(func));
 
     func->StartTarget()->Append(loop);
@@ -215,9 +214,7 @@
 
     auto* loop = b.Loop();
 
-    auto* result = b.Equal(ty.i32(), 1_i, 2_i);
-
-    loop->Body()->Append(result);
+    auto* result = loop->Body()->Append(b.Equal(ty.i32(), 1_i, 2_i));
     loop->Continuing()->Append(b.BreakIf(result, loop));
     loop->Merge()->Append(b.Return(func));
 
@@ -350,20 +347,19 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* l = b.Loop();
-    func->StartTarget()->Append(l);
-
     l->Initializer()->Append(b.NextIteration(l, 1_i));
+    func->StartTarget()->Append(l);
 
     auto* loop_param = b.BlockParam(b.ir.Types().i32());
     l->Body()->SetParams({loop_param});
-    auto* inc = b.Add(b.ir.Types().i32(), loop_param, 1_i);
-    l->Body()->Append(inc);
+
+    auto* inc = l->Body()->Append(b.Add(b.ir.Types().i32(), loop_param, 1_i));
     l->Body()->Append(b.Continue(l, inc));
 
     auto* cont_param = b.BlockParam(b.ir.Types().i32());
     l->Continuing()->SetParams({cont_param});
-    auto* cmp = b.GreaterThan(b.ir.Types().bool_(), cont_param, 5_i);
-    l->Continuing()->Append(cmp);
+
+    auto* cmp = l->Continuing()->Append(b.GreaterThan(b.ir.Types().bool_(), cont_param, 5_i));
     l->Continuing()->Append(b.BreakIf(cmp, l, cont_param));
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -402,25 +398,25 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto* l = b.Loop();
-    func->StartTarget()->Append(l);
-
     l->Initializer()->Append(b.NextIteration(l, 1_i, false));
+    func->StartTarget()->Append(l);
 
     auto* loop_param_a = b.BlockParam(b.ir.Types().i32());
     auto* loop_param_b = b.BlockParam(b.ir.Types().bool_());
     l->Body()->SetParams({loop_param_a, loop_param_b});
-    auto* inc = b.Add(b.ir.Types().i32(), loop_param_a, 1_i);
-    l->Body()->Append(inc);
-    l->Body()->Append(b.Continue(l, inc, loop_param_b));
+
+    auto lb = b.With(l->Body());
+    auto* inc = lb.Add(b.ir.Types().i32(), loop_param_a, 1_i);
+    lb.Continue(l, inc, loop_param_b);
 
     auto* cont_param_a = b.BlockParam(b.ir.Types().i32());
     auto* cont_param_b = b.BlockParam(b.ir.Types().bool_());
     l->Continuing()->SetParams({cont_param_a, cont_param_b});
-    auto* cmp = b.GreaterThan(b.ir.Types().bool_(), cont_param_a, 5_i);
-    l->Continuing()->Append(cmp);
-    auto* not_b = b.Not(b.ir.Types().bool_(), cont_param_b);
-    l->Continuing()->Append(not_b);
-    l->Continuing()->Append(b.BreakIf(cmp, l, cont_param_a, not_b));
+
+    auto cb = b.With(l->Continuing());
+    auto* cmp = cb.GreaterThan(b.ir.Types().bool_(), cont_param_a, 5_i);
+    auto* not_b = cb.Not(b.ir.Types().bool_(), cont_param_b);
+    cb.BreakIf(cmp, l, cont_param_a, not_b);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_switch_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_switch_test.cc
index 215aad8..a2484ef 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_switch_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_switch_test.cc
@@ -243,7 +243,7 @@
     s->Merge()->SetParams({merge_param});
     s->Merge()->Append(b.Return(func));
 
-    func->StartTarget()->SetInstructions({s});
+    func->StartTarget()->Append(s);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -284,7 +284,7 @@
     s->Merge()->SetParams({b.BlockParam(b.ir.Types().i32())});
     s->Merge()->Append(b.Return(func));
 
-    func->StartTarget()->SetInstructions({s});
+    func->StartTarget()->Append(s);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -328,7 +328,7 @@
     s->Merge()->SetParams({merge_param_0, merge_param_1});
     s->Merge()->Append(b.Return(func, merge_param_0));
 
-    func->StartTarget()->SetInstructions({s});
+    func->StartTarget()->Append(s);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
index 5f161be..06ae700 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
@@ -23,9 +23,9 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_NoInit) {
     auto* func = b.Function("foo", ty.void_());
 
-    func->StartTarget()->SetInstructions(
-        {b.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite)),
-         b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -46,11 +46,12 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_WithInit) {
     auto* func = b.Function("foo", ty.void_());
 
+    auto sb = b.With(func->StartTarget());
     auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
     v->SetInitializer(b.Constant(42_i));
 
-    func->StartTarget()->SetInstructions({v, b.Return(func)});
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -73,9 +74,11 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_Name) {
     auto* func = b.Function("foo", ty.void_());
 
+    auto sb = b.With(func->StartTarget());
     auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
-    func->StartTarget()->SetInstructions({v, b.Return(func)});
+        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    sb.Return(func);
+
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -98,16 +101,18 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_DeclInsideBlock) {
     auto* func = b.Function("foo", ty.void_());
 
-    auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
-    v->SetInitializer(b.Constant(42_i));
-
     auto* i = b.If(true);
-    i->True()->SetInstructions({v, b.ExitIf(i)});
-    i->False()->SetInstructions({b.Return(func)});
-    i->Merge()->SetInstructions({b.Return(func)});
 
-    func->StartTarget()->SetInstructions({i});
+    auto tb = b.With(i->True());
+    auto* v =
+        tb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    v->SetInitializer(b.Constant(42_i));
+    tb.ExitIf(i);
+
+    i->False()->Append(b.Return(func));
+    i->Merge()->Append(b.Return(func));
+
+    func->StartTarget()->Append(i);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -139,10 +144,13 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_Load) {
     auto* func = b.Function("foo", ty.void_());
 
+    auto sb = b.With(func->StartTarget());
+
     auto* store_ty = ty.i32();
     auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, store_ty, builtin::Access::kReadWrite));
-    func->StartTarget()->SetInstructions({v, b.Load(v), b.Return(func)});
+        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, store_ty, builtin::Access::kReadWrite));
+    sb.Load(v);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -164,9 +172,11 @@
 TEST_F(SpvGeneratorImplTest, FunctionVar_Store) {
     auto* func = b.Function("foo", ty.void_());
 
+    auto sb = b.With(func->StartTarget());
     auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
-    func->StartTarget()->SetInstructions({v, b.Store(v, 42_i), b.Return(func)});
+        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    sb.Store(v, 42_i);
+    sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
 
@@ -187,8 +197,8 @@
 }
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_NoInit) {
-    b.RootBlock()->SetInstructions(
-        {b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite))});
+    b.RootBlock()->Append(
+        b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite)));
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -210,8 +220,8 @@
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_WithInit) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite));
-    b.RootBlock()->SetInstructions({v});
     v->SetInitializer(b.Constant(42_i));
+    b.RootBlock()->Append(v);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -234,8 +244,9 @@
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_Name) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite));
-    b.RootBlock()->SetInstructions({v});
     v->SetInitializer(b.Constant(42_i));
+    b.RootBlock()->Append(v);
+
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
@@ -264,13 +275,14 @@
 
     auto* store_ty = ty.i32();
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, store_ty, builtin::Access::kReadWrite));
-    b.RootBlock()->SetInstructions({v});
     v->SetInitializer(b.Constant(42_i));
+    b.RootBlock()->Append(v);
 
-    auto* load = b.Load(v);
-    auto* add = b.Add(store_ty, v, 1_i);
-    auto* store = b.Store(v, add);
-    func->StartTarget()->SetInstructions({load, add, store, b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Load(v);
+    auto* add = sb.Add(store_ty, v, 1_i);
+    sb.Store(v, add);
+    sb.Return(func);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -296,8 +308,8 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar) {
-    b.RootBlock()->SetInstructions(
-        {b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite))});
+    b.RootBlock()->Append(
+        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -318,9 +330,8 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar_Name) {
-    auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite));
-    b.RootBlock()->SetInstructions({v});
+    auto* v = b.RootBlock()->Append(
+        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
@@ -348,14 +359,14 @@
     mod.functions.Push(func);
 
     auto* store_ty = ty.i32();
-    auto* v =
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, store_ty, builtin::Access::kReadWrite));
-    b.RootBlock()->SetInstructions({v});
+    auto* v = b.RootBlock()->Append(
+        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, store_ty, builtin::Access::kReadWrite)));
 
-    auto* load = b.Load(v);
-    auto* add = b.Add(store_ty, v, 1_i);
-    auto* store = b.Store(v, add);
-    func->StartTarget()->SetInstructions({load, add, store, b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Load(v);
+    auto* add = sb.Add(store_ty, v, 1_i);
+    sb.Store(v, add);
+    sb.Return(func);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -380,8 +391,8 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar_ZeroInitializeWithExtension) {
-    b.RootBlock()->SetInstructions(
-        {b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite))});
+    b.RootBlock()->Append(
+        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
 
     // Create a generator with the zero_init_workgroup_memory flag set to `true`.
     spirv::GeneratorImplIr gen(&mod, true);
@@ -407,7 +418,7 @@
 TEST_F(SpvGeneratorImplTest, StorageVar) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -437,7 +448,7 @@
 TEST_F(SpvGeneratorImplTest, StorageVar_Name) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
@@ -468,16 +479,17 @@
 TEST_F(SpvGeneratorImplTest, StorageVar_LoadAndStore) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
     mod.functions.Push(func);
 
-    auto* load = b.Load(v);
-    auto* add = b.Add(ty.i32(), v, 1_i);
-    auto* store = b.Store(v, add);
-    func->StartTarget()->SetInstructions({load, add, store, b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Load(v);
+    auto* add = sb.Add(ty.i32(), v, 1_i);
+    sb.Store(v, add);
+    sb.Return(func);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -517,7 +529,7 @@
 TEST_F(SpvGeneratorImplTest, UniformVar) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -547,7 +559,7 @@
 TEST_F(SpvGeneratorImplTest, UniformVar_Name) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
@@ -578,14 +590,15 @@
 TEST_F(SpvGeneratorImplTest, UniformVar_Load) {
     auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->SetInstructions({v});
+    b.RootBlock()->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
     mod.functions.Push(func);
 
-    auto* load = b.Load(v);
-    func->StartTarget()->SetInstructions({load, b.Return(func)});
+    auto sb = b.With(func->StartTarget());
+    sb.Load(v);
+    sb.Return(func);
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader