[ir] Convert instruction to a pointer

This CL updates the instruction class to be a `Castable` and allocated
from an Arena. Uses are updated to store the const pointer.

Bug: tint:1718
Change-Id: Ie0b8353cb0c6fe6e2ba6e01bcd45871891aef903
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112045
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/ir/block.h b/src/tint/ir/block.h
index d27fdf4..ac9028b 100644
--- a/src/tint/ir/block.h
+++ b/src/tint/ir/block.h
@@ -34,7 +34,7 @@
     const FlowNode* branch_target = nullptr;
 
     /// The instructions in the block
-    utils::Vector<Instruction, 16> instructions;
+    utils::Vector<const Instruction*, 16> instructions;
 };
 
 }  // namespace tint::ir
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 6f5e9c6..5c55b91 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -97,79 +97,81 @@
     return next_temp_id++;
 }
 
-Instruction Builder::CreateInstruction(Instruction::Kind kind, const Value* lhs, const Value* rhs) {
-    return Instruction(kind, Temp(), lhs, rhs);
+const Instruction* Builder::CreateInstruction(Instruction::Kind kind,
+                                              const Value* lhs,
+                                              const Value* rhs) {
+    return ir.instructions.Create<ir::Instruction>(kind, Temp(), lhs, rhs);
 }
 
-Instruction Builder::And(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::And(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kAnd, lhs, rhs);
 }
 
-Instruction Builder::Or(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Or(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kOr, lhs, rhs);
 }
 
-Instruction Builder::Xor(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Xor(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kXor, lhs, rhs);
 }
 
-Instruction Builder::LogicalAnd(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::LogicalAnd(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kLogicalAnd, lhs, rhs);
 }
 
-Instruction Builder::LogicalOr(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::LogicalOr(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kLogicalOr, lhs, rhs);
 }
 
-Instruction Builder::Equal(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Equal(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kEqual, lhs, rhs);
 }
 
-Instruction Builder::NotEqual(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::NotEqual(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kNotEqual, lhs, rhs);
 }
 
-Instruction Builder::LessThan(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::LessThan(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kLessThan, lhs, rhs);
 }
 
-Instruction Builder::GreaterThan(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::GreaterThan(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kGreaterThan, lhs, rhs);
 }
 
-Instruction Builder::LessThanEqual(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::LessThanEqual(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kLessThanEqual, lhs, rhs);
 }
 
-Instruction Builder::GreaterThanEqual(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::GreaterThanEqual(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kGreaterThanEqual, lhs, rhs);
 }
 
-Instruction Builder::ShiftLeft(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::ShiftLeft(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kShiftLeft, lhs, rhs);
 }
 
-Instruction Builder::ShiftRight(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::ShiftRight(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kShiftRight, lhs, rhs);
 }
 
-Instruction Builder::Add(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Add(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kAdd, lhs, rhs);
 }
 
-Instruction Builder::Subtract(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Subtract(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kSubtract, lhs, rhs);
 }
 
-Instruction Builder::Multiply(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Multiply(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kMultiply, lhs, rhs);
 }
 
-Instruction Builder::Divide(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Divide(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kDivide, lhs, rhs);
 }
 
-Instruction Builder::Modulo(const Value* lhs, const Value* rhs) {
+const Instruction* Builder::Modulo(const Value* lhs, const Value* rhs) {
     return CreateInstruction(Instruction::Kind::kModulo, lhs, rhs);
 }
 
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index bc30a95..d5065b8 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -102,115 +102,117 @@
     /// @param lhs the left-hand-side of the operation
     /// @param rhs the right-hand-side of the operation
     /// @returns the operation
-    Instruction CreateInstruction(Instruction::Kind kind, const Value* lhs, const Value* rhs);
+    const Instruction* CreateInstruction(Instruction::Kind kind,
+                                         const Value* lhs,
+                                         const Value* rhs);
 
     /// Creates an And operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction And(const Value* lhs, const Value* rhs);
+    const Instruction* And(const Value* lhs, const Value* rhs);
 
     /// Creates an Or operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Or(const Value* lhs, const Value* rhs);
+    const Instruction* Or(const Value* lhs, const Value* rhs);
 
     /// Creates an Xor operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Xor(const Value* lhs, const Value* rhs);
+    const Instruction* Xor(const Value* lhs, const Value* rhs);
 
     /// Creates an LogicalAnd operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction LogicalAnd(const Value* lhs, const Value* rhs);
+    const Instruction* LogicalAnd(const Value* lhs, const Value* rhs);
 
     /// Creates an LogicalOr operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction LogicalOr(const Value* lhs, const Value* rhs);
+    const Instruction* LogicalOr(const Value* lhs, const Value* rhs);
 
     /// Creates an Equal operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Equal(const Value* lhs, const Value* rhs);
+    const Instruction* Equal(const Value* lhs, const Value* rhs);
 
     /// Creates an NotEqual operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction NotEqual(const Value* lhs, const Value* rhs);
+    const Instruction* NotEqual(const Value* lhs, const Value* rhs);
 
     /// Creates an LessThan operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction LessThan(const Value* lhs, const Value* rhs);
+    const Instruction* LessThan(const Value* lhs, const Value* rhs);
 
     /// Creates an GreaterThan operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction GreaterThan(const Value* lhs, const Value* rhs);
+    const Instruction* GreaterThan(const Value* lhs, const Value* rhs);
 
     /// Creates an LessThanEqual operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction LessThanEqual(const Value* lhs, const Value* rhs);
+    const Instruction* LessThanEqual(const Value* lhs, const Value* rhs);
 
     /// Creates an GreaterThanEqual operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction GreaterThanEqual(const Value* lhs, const Value* rhs);
+    const Instruction* GreaterThanEqual(const Value* lhs, const Value* rhs);
 
     /// Creates an ShiftLeft operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction ShiftLeft(const Value* lhs, const Value* rhs);
+    const Instruction* ShiftLeft(const Value* lhs, const Value* rhs);
 
     /// Creates an ShiftRight operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction ShiftRight(const Value* lhs, const Value* rhs);
+    const Instruction* ShiftRight(const Value* lhs, const Value* rhs);
 
     /// Creates an Add operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Add(const Value* lhs, const Value* rhs);
+    const Instruction* Add(const Value* lhs, const Value* rhs);
 
     /// Creates an Subtract operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Subtract(const Value* lhs, const Value* rhs);
+    const Instruction* Subtract(const Value* lhs, const Value* rhs);
 
     /// Creates an Multiply operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Multiply(const Value* lhs, const Value* rhs);
+    const Instruction* Multiply(const Value* lhs, const Value* rhs);
 
     /// Creates an Divide operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Divide(const Value* lhs, const Value* rhs);
+    const Instruction* Divide(const Value* lhs, const Value* rhs);
 
     /// Creates an Modulo operation
     /// @param lhs the lhs of the add
     /// @param rhs the rhs of the add
     /// @returns the operation
-    Instruction Modulo(const Value* lhs, const Value* rhs);
+    const Instruction* Modulo(const Value* lhs, const Value* rhs);
 
     /// @returns a unique temp id
     Temp::Id AllocateTempId();
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index 7700512..2286bf4 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -562,7 +562,7 @@
         return utils::Failure;
     }
 
-    Instruction instr;
+    const Instruction* instr = nullptr;
     switch (expr->op) {
         case ast::BinaryOp::kAnd:
             instr = builder.And(lhs.Get(), rhs.Get());
@@ -623,9 +623,8 @@
             return utils::Failure;
     }
 
-    auto* result = instr.Result();
     current_flow_block->instructions.Push(instr);
-    return utils::Result<const Value*>(result);
+    return utils::Result<const Value*>(instr->Result());
 }
 
 utils::Result<const Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
diff --git a/src/tint/ir/disassembler.cc b/src/tint/ir/disassembler.cc
index f98950f..e2749a1 100644
--- a/src/tint/ir/disassembler.cc
+++ b/src/tint/ir/disassembler.cc
@@ -62,8 +62,8 @@
 }
 
 void Disassembler::EmitBlockInstructions(const Block* b) {
-    for (const auto& instr : b->instructions) {
-        out_ << instr << std::endl;
+    for (const auto* instr : b->instructions) {
+        out_ << *instr << std::endl;
     }
 }
 
diff --git a/src/tint/ir/instruction.cc b/src/tint/ir/instruction.cc
index a46d17c..6c0f176 100644
--- a/src/tint/ir/instruction.cc
+++ b/src/tint/ir/instruction.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/ir/instruction.h"
 
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Instruction);
+
 namespace tint::ir {
 
 Instruction::Instruction() {}
diff --git a/src/tint/ir/instruction.h b/src/tint/ir/instruction.h
index 1735115..461b1f7 100644
--- a/src/tint/ir/instruction.h
+++ b/src/tint/ir/instruction.h
@@ -17,6 +17,7 @@
 
 #include <ostream>
 
+#include "src/tint/castable.h"
 #include "src/tint/debug.h"
 #include "src/tint/ir/value.h"
 #include "src/tint/utils/vector.h"
@@ -24,7 +25,7 @@
 namespace tint::ir {
 
 /// An instruction in the IR.
-class Instruction {
+class Instruction : public Castable<Instruction> {
   public:
     /// The kind of instruction.
     enum class Kind {
diff --git a/src/tint/ir/instruction_test.cc b/src/tint/ir/instruction_test.cc
index d6c8d8a..0957903 100644
--- a/src/tint/ir/instruction_test.cc
+++ b/src/tint/ir/instruction_test.cc
@@ -26,27 +26,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.And(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAnd);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAnd);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 & 2");
 }
 
@@ -54,27 +54,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Or(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kOr);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kOr);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 | 2");
 }
 
@@ -82,27 +82,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Xor(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kXor);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kXor);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 ^ 2");
 }
 
@@ -110,27 +110,28 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr =
+        b.builder.LogicalAnd(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalAnd);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalAnd);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 && 2");
 }
 
@@ -138,27 +139,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.LogicalOr(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLogicalOr);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLogicalOr);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 || 2");
 }
 
@@ -166,27 +167,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Equal(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kEqual);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kEqual);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 == 2");
 }
 
@@ -194,27 +195,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.NotEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kNotEqual);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kNotEqual);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 != 2");
 }
 
@@ -222,27 +223,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.LessThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThan);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThan);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 < 2");
 }
 
@@ -250,27 +251,28 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr =
+        b.builder.GreaterThan(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThan);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThan);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 > 2");
 }
 
@@ -278,27 +280,28 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr =
+        b.builder.LessThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kLessThanEqual);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kLessThanEqual);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 <= 2");
 }
 
@@ -306,27 +309,28 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr =
+        b.builder.GreaterThanEqual(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kGreaterThanEqual);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kGreaterThanEqual);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 >= 2");
 }
 
@@ -334,27 +338,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.ShiftLeft(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftLeft);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftLeft);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 << 2");
 }
 
@@ -362,27 +366,28 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr =
+        b.builder.ShiftRight(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kShiftRight);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kShiftRight);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 >> 2");
 }
 
@@ -390,27 +395,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Add(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kAdd);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kAdd);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 + 2");
 }
 
@@ -418,27 +423,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Subtract(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kSubtract);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kSubtract);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 - 2");
 }
 
@@ -446,27 +451,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Multiply(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kMultiply);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kMultiply);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 * 2");
 }
 
@@ -474,27 +479,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Divide(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kDivide);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kDivide);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 / 2");
 }
 
@@ -502,27 +507,27 @@
     auto& b = CreateEmptyBuilder();
 
     b.builder.next_temp_id = Temp::Id(42);
-    auto instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
+    const auto* instr = b.builder.Modulo(b.builder.Constant(i32(4)), b.builder.Constant(i32(2)));
 
-    EXPECT_EQ(instr.GetKind(), Instruction::Kind::kModulo);
+    EXPECT_EQ(instr->GetKind(), Instruction::Kind::kModulo);
 
-    ASSERT_TRUE(instr.Result()->Is<Temp>());
-    EXPECT_EQ(Temp::Id(42), instr.Result()->As<Temp>()->AsId());
+    ASSERT_TRUE(instr->Result()->Is<Temp>());
+    EXPECT_EQ(Temp::Id(42), instr->Result()->As<Temp>()->AsId());
 
-    ASSERT_TRUE(instr.HasLHS());
-    ASSERT_TRUE(instr.LHS()->Is<Constant>());
-    auto lhs = instr.LHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasLHS());
+    ASSERT_TRUE(instr->LHS()->Is<Constant>());
+    auto lhs = instr->LHS()->As<Constant>();
     ASSERT_TRUE(lhs->IsI32());
     EXPECT_EQ(i32(4), lhs->AsI32());
 
-    ASSERT_TRUE(instr.HasRHS());
-    ASSERT_TRUE(instr.RHS()->Is<Constant>());
-    auto rhs = instr.RHS()->As<Constant>();
+    ASSERT_TRUE(instr->HasRHS());
+    ASSERT_TRUE(instr->RHS()->Is<Constant>());
+    auto rhs = instr->RHS()->As<Constant>();
     ASSERT_TRUE(rhs->IsI32());
     EXPECT_EQ(i32(2), rhs->AsI32());
 
     std::stringstream str;
-    str << instr;
+    str << *instr;
     EXPECT_EQ(str.str(), "%42 = 4 % 2");
 }
 
diff --git a/src/tint/ir/module.h b/src/tint/ir/module.h
index 1e2f8b0..d95a13e 100644
--- a/src/tint/ir/module.h
+++ b/src/tint/ir/module.h
@@ -18,6 +18,7 @@
 #include <string>
 
 #include "src/tint/ir/function.h"
+#include "src/tint/ir/instruction.h"
 #include "src/tint/ir/value.h"
 #include "src/tint/utils/block_allocator.h"
 #include "src/tint/utils/result.h"
@@ -69,6 +70,8 @@
     utils::BlockAllocator<FlowNode> flow_nodes;
     /// The value allocator
     utils::BlockAllocator<Value> values;
+    /// The instruction allocator
+    utils::BlockAllocator<Instruction> instructions;
 
     /// List of functions in the program
     utils::Vector<Function*, 8> functions;