Commit ca3cf93b21

Andrew Kelley <andrew@ziglang.org>
2023-05-04 04:12:53
stage2: move most simple values to InternPool
1 parent 836d8a1
src/codegen/c.zig
@@ -1191,7 +1191,7 @@ pub const DeclGen = struct {
                 }
             },
             .Bool => {
-                if (val.toBool()) {
+                if (val.toBool(mod)) {
                     return writer.writeAll("true");
                 } else {
                     return writer.writeAll("false");
src/codegen/llvm.zig
@@ -2793,7 +2793,7 @@ pub const DeclGen = struct {
         if (std.debug.runtime_safety and false) check: {
             if (t.zigTypeTag(mod) == .Opaque) break :check;
             if (!t.hasRuntimeBits(mod)) break :check;
-            if (!llvm_ty.isSized().toBool()) break :check;
+            if (!llvm_ty.isSized().toBool(mod)) break :check;
 
             const zig_size = t.abiSize(mod);
             const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty);
@@ -3272,7 +3272,7 @@ pub const DeclGen = struct {
         switch (tv.ty.zigTypeTag(mod)) {
             .Bool => {
                 const llvm_type = try dg.lowerType(tv.ty);
-                return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
+                return if (tv.val.toBool(mod)) llvm_type.constAllOnes() else llvm_type.constNull();
             },
             // TODO this duplicates code with Pointer but they should share the handling
             // of the tv.val.tag() and then Int should do extra constPtrToInt on top
src/codegen/spirv.zig
@@ -621,7 +621,7 @@ pub const DeclGen = struct {
             switch (ty.zigTypeTag(mod)) {
                 .Int => try self.addInt(ty, val),
                 .Float => try self.addFloat(ty, val),
-                .Bool => try self.addConstBool(val.toBool()),
+                .Bool => try self.addConstBool(val.toBool(mod)),
                 .Array => switch (val.tag()) {
                     .aggregate => {
                         const elem_vals = val.castTag(.aggregate).?.data;
@@ -989,8 +989,8 @@ pub const DeclGen = struct {
                 }
             },
             .Bool => switch (repr) {
-                .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
-                .indirect => return try self.spv.constInt(result_ty_ref, @boolToInt(val.toBool())),
+                .direct => return try self.spv.constBool(result_ty_ref, val.toBool(mod)),
+                .indirect => return try self.spv.constInt(result_ty_ref, @boolToInt(val.toBool(mod))),
             },
             .Float => return switch (ty.floatBits(target)) {
                 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16) } } }),
src/Air.zig
@@ -899,8 +899,10 @@ pub const Inst = struct {
         type_info_type = @enumToInt(InternPool.Index.type_info_type),
         manyptr_u8_type = @enumToInt(InternPool.Index.manyptr_u8_type),
         manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type),
+        manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type),
         single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type),
         const_slice_u8_type = @enumToInt(InternPool.Index.const_slice_u8_type),
+        const_slice_u8_sentinel_0_type = @enumToInt(InternPool.Index.const_slice_u8_sentinel_0_type),
         anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type),
         generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type),
         var_args_param_type = @enumToInt(InternPool.Index.var_args_param_type),
@@ -908,6 +910,7 @@ pub const Inst = struct {
         undef = @enumToInt(InternPool.Index.undef),
         zero = @enumToInt(InternPool.Index.zero),
         zero_usize = @enumToInt(InternPool.Index.zero_usize),
+        zero_u8 = @enumToInt(InternPool.Index.zero_u8),
         one = @enumToInt(InternPool.Index.one),
         one_usize = @enumToInt(InternPool.Index.one_usize),
         calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c),
src/codegen.zig
@@ -494,7 +494,7 @@ pub fn generateSymbol(
             return Result.ok;
         },
         .Bool => {
-            const x: u8 = @boolToInt(typed_value.val.toBool());
+            const x: u8 = @boolToInt(typed_value.val.toBool(mod));
             try code.append(x);
             return Result.ok;
         },
@@ -1213,7 +1213,7 @@ pub fn genTypedValue(
             }
         },
         .Bool => {
-            return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) });
+            return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool(mod)) });
         },
         .Optional => {
             if (typed_value.ty.isPtrLikeOptional(mod)) {
src/InternPool.zig
@@ -318,8 +318,10 @@ pub const Index = enum(u32) {
     type_info_type,
     manyptr_u8_type,
     manyptr_const_u8_type,
+    manyptr_const_u8_sentinel_0_type,
     single_const_pointer_to_comptime_int_type,
     const_slice_u8_type,
+    const_slice_u8_sentinel_0_type,
     anyerror_void_error_union_type,
     generic_poison_type,
     var_args_param_type,
@@ -331,6 +333,8 @@ pub const Index = enum(u32) {
     zero,
     /// `0` (usize)
     zero_usize,
+    /// `0` (u8)
+    zero_u8,
     /// `1` (comptime_int)
     one,
     /// `1` (usize)
@@ -489,24 +493,43 @@ pub const static_keys = [_]Key{
         .size = .Many,
     } },
 
+    // manyptr_const_u8_type
     .{ .ptr_type = .{
         .elem_type = .u8_type,
         .size = .Many,
         .is_const = true,
     } },
 
+    // manyptr_const_u8_sentinel_0_type
+    .{ .ptr_type = .{
+        .elem_type = .u8_type,
+        .sentinel = .zero_u8,
+        .size = .Many,
+        .is_const = true,
+    } },
+
     .{ .ptr_type = .{
         .elem_type = .comptime_int_type,
         .size = .One,
         .is_const = true,
     } },
 
+    // const_slice_u8_type
     .{ .ptr_type = .{
         .elem_type = .u8_type,
         .size = .Slice,
         .is_const = true,
     } },
 
+    // const_slice_u8_sentinel_0_type
+    .{ .ptr_type = .{
+        .elem_type = .u8_type,
+        .sentinel = .zero_u8,
+        .size = .Slice,
+        .is_const = true,
+    } },
+
+    // anyerror_void_error_union_type
     .{ .error_union_type = .{
         .error_set_type = .anyerror_type,
         .payload_type = .void_type,
@@ -541,6 +564,14 @@ pub const static_keys = [_]Key{
         },
     } },
 
+    .{ .int = .{
+        .ty = .u8_type,
+        .big_int = .{
+            .limbs = &.{0},
+            .positive = true,
+        },
+    } },
+
     .{ .int = .{
         .ty = .comptime_int_type,
         .big_int = .{
src/Module.zig
@@ -4847,31 +4847,37 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
     decl.owns_tv = false;
     var queue_linker_work = false;
     var is_extern = false;
-    switch (decl_tv.val.tag()) {
-        .variable => {
-            const variable = decl_tv.val.castTag(.variable).?.data;
-            if (variable.owner_decl == decl_index) {
-                decl.owns_tv = true;
-                queue_linker_work = true;
-
-                const copied_init = try variable.init.copy(decl_arena_allocator);
-                variable.init = copied_init;
-            }
-        },
-        .extern_fn => {
-            const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
-            if (extern_fn.owner_decl == decl_index) {
-                decl.owns_tv = true;
-                queue_linker_work = true;
-                is_extern = true;
-            }
-        },
-
+    switch (decl_tv.val.ip_index) {
         .generic_poison => unreachable,
-        .unreachable_value => unreachable,
+        .none => switch (decl_tv.val.tag()) {
+            .variable => {
+                const variable = decl_tv.val.castTag(.variable).?.data;
+                if (variable.owner_decl == decl_index) {
+                    decl.owns_tv = true;
+                    queue_linker_work = true;
+
+                    const copied_init = try variable.init.copy(decl_arena_allocator);
+                    variable.init = copied_init;
+                }
+            },
+            .extern_fn => {
+                const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
+                if (extern_fn.owner_decl == decl_index) {
+                    decl.owns_tv = true;
+                    queue_linker_work = true;
+                    is_extern = true;
+                }
+            },
+
+            .unreachable_value => unreachable,
 
-        .function => {},
+            .function => {},
 
+            else => {
+                log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
+                queue_linker_work = true;
+            },
+        },
         else => {
             log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name });
             queue_linker_work = true;
src/Sema.zig
@@ -1569,6 +1569,7 @@ fn analyzeBodyInner(
             },
             .condbr => blk: {
                 if (!block.is_comptime) break sema.zirCondbr(block, inst);
+                const mod = sema.mod;
                 // Same as condbr_inline. TODO https://github.com/ziglang/zig/issues/8220
                 const inst_data = datas[inst].pl_node;
                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
@@ -1579,7 +1580,7 @@ fn analyzeBodyInner(
                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                const inline_body = if (cond.val.toBool()) then_body else else_body;
+                const inline_body = if (cond.val.toBool(mod)) then_body else else_body;
 
                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
@@ -1591,6 +1592,7 @@ fn analyzeBodyInner(
                 }
             },
             .condbr_inline => blk: {
+                const mod = sema.mod;
                 const inst_data = datas[inst].pl_node;
                 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
                 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
@@ -1600,7 +1602,7 @@ fn analyzeBodyInner(
                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                const inline_body = if (cond.val.toBool()) then_body else else_body;
+                const inline_body = if (cond.val.toBool(mod)) then_body else else_body;
 
                 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
                 const old_runtime_index = block.runtime_index;
@@ -1634,7 +1636,7 @@ fn analyzeBodyInner(
                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                if (is_non_err_val.toBool()) {
+                if (is_non_err_val.toBool(mod)) {
                     break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
                 }
                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
@@ -1647,6 +1649,7 @@ fn analyzeBodyInner(
             },
             .try_ptr => blk: {
                 if (!block.is_comptime) break :blk try sema.zirTryPtr(block, inst);
+                const mod = sema.mod;
                 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
                 const src = inst_data.src();
                 const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
@@ -1660,7 +1663,7 @@ fn analyzeBodyInner(
                     if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                if (is_non_err_val.toBool()) {
+                if (is_non_err_val.toBool(mod)) {
                     break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
                 }
                 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
@@ -1741,11 +1744,12 @@ fn resolveConstBool(
     zir_ref: Zir.Inst.Ref,
     reason: []const u8,
 ) !bool {
+    const mod = sema.mod;
     const air_inst = try sema.resolveInst(zir_ref);
     const wanted_type = Type.bool;
     const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
     const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
-    return val.toBool();
+    return val.toBool(mod);
 }
 
 pub fn resolveConstString(
@@ -1843,9 +1847,12 @@ fn resolveConstMaybeUndefVal(
     reason: []const u8,
 ) CompileError!Value {
     if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| {
-        switch (val.tag()) {
-            .variable => return sema.failWithNeededComptime(block, src, reason),
+        switch (val.ip_index) {
             .generic_poison => return error.GenericPoison,
+            .none => switch (val.tag()) {
+                .variable => return sema.failWithNeededComptime(block, src, reason),
+                else => return val,
+            },
             else => return val,
         }
     }
@@ -1862,10 +1869,13 @@ fn resolveConstValue(
     reason: []const u8,
 ) CompileError!Value {
     if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
-        switch (val.tag()) {
-            .undef => return sema.failWithUseOfUndef(block, src),
-            .variable => return sema.failWithNeededComptime(block, src, reason),
+        switch (val.ip_index) {
             .generic_poison => return error.GenericPoison,
+            .none => switch (val.tag()) {
+                .undef => return sema.failWithUseOfUndef(block, src),
+                .variable => return sema.failWithNeededComptime(block, src, reason),
+                else => return val,
+            },
             else => return val,
         }
     }
@@ -1900,12 +1910,11 @@ fn resolveMaybeUndefVal(
     const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
     switch (val.ip_index) {
         .generic_poison => return error.GenericPoison,
-        else => return val,
         .none => switch (val.tag()) {
             .variable => return null,
-            .generic_poison => return error.GenericPoison,
             else => return val,
         },
+        else => return val,
     }
 }
 
@@ -1919,12 +1928,18 @@ fn resolveMaybeUndefValIntable(
 ) CompileError!?Value {
     const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
     var check = val;
-    while (true) switch (check.tag()) {
-        .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
-        .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
-        .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
-        .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
+    while (true) switch (check.ip_index) {
         .generic_poison => return error.GenericPoison,
+        .none => switch (check.tag()) {
+            .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
+            .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
+            .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
+            .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
+            else => {
+                try sema.resolveLazyValue(val);
+                return val;
+            },
+        },
         else => {
             try sema.resolveLazyValue(val);
             return val;
@@ -6208,12 +6223,13 @@ fn popErrorReturnTrace(
     operand: Air.Inst.Ref,
     saved_error_trace_index: Air.Inst.Ref,
 ) CompileError!void {
+    const mod = sema.mod;
     var is_non_error: ?bool = null;
     var is_non_error_inst: Air.Inst.Ref = undefined;
     if (operand != .none) {
         is_non_error_inst = try sema.analyzeIsNonErr(block, src, operand);
         if (try sema.resolveDefinedValue(block, src, is_non_error_inst)) |cond_val|
-            is_non_error = cond_val.toBool();
+            is_non_error = cond_val.toBool(mod);
     } else is_non_error = true; // no operand means pop unconditionally
 
     if (is_non_error == true) {
@@ -7222,7 +7238,7 @@ fn analyzeInlineCallArg(
                     if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                switch (arg_val.tag()) {
+                switch (arg_val.ip_index) {
                     .generic_poison, .generic_poison_type => {
                         // This function is currently evaluated as part of an as-of-yet unresolvable
                         // parameter or return type.
@@ -7261,7 +7277,7 @@ fn analyzeInlineCallArg(
                     if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
                     return err;
                 };
-                switch (arg_val.tag()) {
+                switch (arg_val.ip_index) {
                     .generic_poison, .generic_poison_type => {
                         // This function is currently evaluated as part of an as-of-yet unresolvable
                         // parameter or return type.
@@ -7443,13 +7459,13 @@ fn instantiateGenericCall(
                 arg_ty.hashWithHasher(&hasher, mod);
                 generic_args[i] = .{
                     .ty = arg_ty,
-                    .val = Value.initTag(.generic_poison),
+                    .val = Value.generic_poison,
                     .is_anytype = true,
                 };
             } else {
                 generic_args[i] = .{
                     .ty = arg_ty,
-                    .val = Value.initTag(.generic_poison),
+                    .val = Value.generic_poison,
                     .is_anytype = false,
                 };
             }
@@ -7815,7 +7831,7 @@ fn resolveGenericInstantiationType(
         } else {
             child_sema.comptime_args[arg_i] = .{
                 .ty = copied_arg_ty,
-                .val = Value.initTag(.generic_poison),
+                .val = Value.generic_poison,
             };
         }
 
@@ -8780,9 +8796,9 @@ fn resolveGenericBody(
     switch (err) {
         error.GenericPoison => {
             if (dest_ty.ip_index == .type_type) {
-                return Value.initTag(.generic_poison_type);
+                return Value.generic_poison_type;
             } else {
-                return Value.initTag(.generic_poison);
+                return Value.generic_poison;
             }
         },
         else => |e| return e,
@@ -9394,7 +9410,7 @@ fn zirParam(
     if (is_comptime) {
         // If this is a comptime parameter we can add a constant generic_poison
         // since this is also a generic parameter.
-        const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
+        const result = try sema.addConstant(param_ty, Value.generic_poison);
         sema.inst_map.putAssumeCapacityNoClobber(inst, result);
     } else {
         // Otherwise we need a dummy runtime instruction.
@@ -11819,8 +11835,9 @@ fn validateSwitchItemBool(
     src_node_offset: i32,
     switch_prong_src: Module.SwitchProngSrc,
 ) CompileError!void {
+    const mod = sema.mod;
     const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
-    if (item_val.toBool()) {
+    if (item_val.toBool(mod)) {
         true_count.* += 1;
     } else {
         false_count.* += 1;
@@ -15462,7 +15479,7 @@ fn cmpSelf(
             } else {
                 if (resolved_type.zigTypeTag(mod) == .Bool) {
                     // We can lower bool eq/neq more efficiently.
-                    return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
+                    return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(mod), rhs_src);
                 }
                 break :src rhs_src;
             }
@@ -15472,7 +15489,7 @@ fn cmpSelf(
             if (resolved_type.zigTypeTag(mod) == .Bool) {
                 if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
                     if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
-                    return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
+                    return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(mod), lhs_src);
                 }
             }
             break :src lhs_src;
@@ -16815,6 +16832,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     const tracy = trace(@src());
     defer tracy.end();
 
+    const mod = sema.mod;
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
@@ -16824,7 +16842,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     if (try sema.resolveMaybeUndefVal(operand)) |val| {
         return if (val.isUndef())
             sema.addConstUndef(Type.bool)
-        else if (val.toBool())
+        else if (val.toBool(mod))
             Air.Inst.Ref.bool_false
         else
             Air.Inst.Ref.bool_true;
@@ -16842,6 +16860,7 @@ fn zirBoolBr(
     const tracy = trace(@src());
     defer tracy.end();
 
+    const mod = sema.mod;
     const datas = sema.code.instructions.items(.data);
     const inst_data = datas[inst].bool_br;
     const lhs = try sema.resolveInst(inst_data.lhs);
@@ -16851,9 +16870,9 @@ fn zirBoolBr(
     const gpa = sema.gpa;
 
     if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {
-        if (is_bool_or and lhs_val.toBool()) {
+        if (is_bool_or and lhs_val.toBool(mod)) {
             return Air.Inst.Ref.bool_true;
-        } else if (!is_bool_or and !lhs_val.toBool()) {
+        } else if (!is_bool_or and !lhs_val.toBool(mod)) {
             return Air.Inst.Ref.bool_false;
         }
         // comptime-known left-hand side. No need for a block here; the result
@@ -16897,9 +16916,9 @@ fn zirBoolBr(
     const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
     if (!sema.typeOf(rhs_result).isNoReturn()) {
         if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| {
-            if (is_bool_or and rhs_val.toBool()) {
+            if (is_bool_or and rhs_val.toBool(mod)) {
                 return Air.Inst.Ref.bool_true;
-            } else if (!is_bool_or and !rhs_val.toBool()) {
+            } else if (!is_bool_or and !rhs_val.toBool(mod)) {
                 return Air.Inst.Ref.bool_false;
             }
         }
@@ -17053,7 +17072,7 @@ fn zirCondbr(
     const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src);
 
     if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
-        const body = if (cond_val.toBool()) then_body else else_body;
+        const body = if (cond_val.toBool(mod)) then_body else else_body;
 
         try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src);
         // We use `analyzeBodyInner` since we want to propagate any possible
@@ -17126,7 +17145,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
     if (is_non_err != .none) {
         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
-        if (is_non_err_val.toBool()) {
+        if (is_non_err_val.toBool(mod)) {
             return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false);
         }
         // We can analyze the body directly in the parent block because we know there are
@@ -17173,7 +17192,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
     const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
     if (is_non_err != .none) {
         const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
-        if (is_non_err_val.toBool()) {
+        if (is_non_err_val.toBool(mod)) {
             return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
         }
         // We can analyze the body directly in the parent block because we know there are
@@ -18509,11 +18528,12 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
 }
 
 fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+    const mod = sema.mod;
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const operand = try sema.resolveInst(inst_data.operand);
     if (try sema.resolveMaybeUndefVal(operand)) |val| {
         if (val.isUndef()) return sema.addConstUndef(Type.u1);
-        if (val.toBool()) return sema.addConstant(Type.u1, Value.one);
+        if (val.toBool(mod)) return sema.addConstant(Type.u1, Value.one);
         return sema.addConstant(Type.u1, Value.zero);
     }
     return block.addUnOp(.bool_to_int, operand);
@@ -18811,12 +18831,12 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
 
             const ty = try Type.ptr(sema.arena, mod, .{
                 .size = ptr_size,
-                .mutable = !is_const_val.toBool(),
-                .@"volatile" = is_volatile_val.toBool(),
+                .mutable = !is_const_val.toBool(mod),
+                .@"volatile" = is_volatile_val.toBool(mod),
                 .@"align" = abi_align,
                 .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace),
                 .pointee_type = try elem_ty.copy(sema.arena),
-                .@"allowzero" = is_allowzero_val.toBool(),
+                .@"allowzero" = is_allowzero_val.toBool(mod),
                 .sentinel = actual_sentinel,
             });
             return sema.addType(ty);
@@ -18932,7 +18952,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
                 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
             }
 
-            return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool());
+            return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool(mod));
         },
         .Enum => {
             const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
@@ -18961,7 +18981,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
             const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
             enum_ty_payload.* = .{
                 .base = .{
-                    .tag = if (!is_exhaustive_val.toBool())
+                    .tag = if (!is_exhaustive_val.toBool(mod))
                         .enum_nonexhaustive
                     else
                         .enum_full,
@@ -19295,9 +19315,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
             // alignment: comptime_int,
             const alignment_val = struct_val[1];
             // is_generic: bool,
-            const is_generic = struct_val[2].toBool();
+            const is_generic = struct_val[2].toBool(mod);
             // is_var_args: bool,
-            const is_var_args = struct_val[3].toBool();
+            const is_var_args = struct_val[3].toBool(mod);
             // return_type: ?type,
             const return_type_val = struct_val[4];
             // args: []const Param,
@@ -19339,9 +19359,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
                 const arg_val = arg.castTag(.aggregate).?.data;
                 // TODO use reflection instead of magic numbers here
                 // is_generic: bool,
-                const arg_is_generic = arg_val[0].toBool();
+                const arg_is_generic = arg_val[0].toBool(mod);
                 // is_noalias: bool,
-                const arg_is_noalias = arg_val[1].toBool();
+                const arg_is_noalias = arg_val[1].toBool(mod);
                 // type: ?type,
                 const param_type_opt_val = arg_val[2];
 
@@ -19455,9 +19475,9 @@ fn reifyStruct(
 
         if (layout == .Packed) {
             if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
-            if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
+            if (is_comptime_val.toBool(mod)) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
         }
-        if (layout == .Extern and is_comptime_val.toBool()) {
+        if (layout == .Extern and is_comptime_val.toBool(mod)) {
             return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
         }
 
@@ -19499,7 +19519,7 @@ fn reifyStruct(
                 opt_val;
             break :blk try payload_val.copy(new_decl_arena_allocator);
         } else Value.initTag(.unreachable_value);
-        if (is_comptime_val.toBool() and default_val.tag() == .unreachable_value) {
+        if (is_comptime_val.toBool(mod) and default_val.tag() == .unreachable_value) {
             return sema.fail(block, src, "comptime field without default initialization value", .{});
         }
 
@@ -19508,7 +19528,7 @@ fn reifyStruct(
             .ty = field_ty,
             .abi_align = abi_align,
             .default_val = default_val,
-            .is_comptime = is_comptime_val.toBool(),
+            .is_comptime = is_comptime_val.toBool(mod),
             .offset = undefined,
         };
 
@@ -21446,7 +21466,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
                 const elems = try sema.gpa.alloc(Value, vec_len);
                 for (elems, 0..) |*elem, i| {
                     const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf);
-                    const should_choose_a = pred_elem_val.toBool();
+                    const should_choose_a = pred_elem_val.toBool(mod);
                     if (should_choose_a) {
                         elem.* = a_val.elemValueBuffer(sema.mod, i, &buf);
                     } else {
@@ -22956,7 +22976,7 @@ fn resolveExternOptions(
         .name = name,
         .library_name = library_name,
         .linkage = linkage,
-        .is_thread_local = is_thread_local_val.toBool(),
+        .is_thread_local = is_thread_local_val.toBool(mod),
     };
 }
 
@@ -31760,8 +31780,10 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
         .enum_literal_type,
         .manyptr_u8_type,
         .manyptr_const_u8_type,
+        .manyptr_const_u8_sentinel_0_type,
         .single_const_pointer_to_comptime_int_type,
         .const_slice_u8_type,
+        .const_slice_u8_sentinel_0_type,
         .anyerror_void_error_union_type,
         .generic_poison_type,
         .var_args_param_type,
@@ -31771,6 +31793,7 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
         .undef => unreachable,
         .zero => unreachable,
         .zero_usize => unreachable,
+        .zero_u8 => unreachable,
         .one => unreachable,
         .one_usize => unreachable,
         .calling_convention_c => unreachable,
@@ -34225,12 +34248,9 @@ fn intFitsInType(
     switch (val.tag()) {
         .zero,
         .undef,
-        .bool_false,
         => return true,
 
-        .one,
-        .bool_true,
-        => switch (ty.zigTypeTag(mod)) {
+        .one => switch (ty.zigTypeTag(mod)) {
             .Int => {
                 const info = ty.intInfo(mod);
                 return switch (info.signedness) {
src/type.zig
@@ -2054,22 +2054,22 @@ pub const Type = struct {
     pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value {
         if (self.ip_index != .none) return self.ip_index.toValue();
         switch (self.tag()) {
-            .u1 => return Value.initTag(.u1_type),
-            .u8 => return Value.initTag(.u8_type),
-            .i8 => return Value.initTag(.i8_type),
-            .u16 => return Value.initTag(.u16_type),
-            .u29 => return Value.initTag(.u29_type),
-            .i16 => return Value.initTag(.i16_type),
-            .u32 => return Value.initTag(.u32_type),
-            .i32 => return Value.initTag(.i32_type),
-            .u64 => return Value.initTag(.u64_type),
-            .i64 => return Value.initTag(.i64_type),
-            .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
-            .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
-            .const_slice_u8_sentinel_0 => return Value.initTag(.const_slice_u8_sentinel_0_type),
-            .manyptr_u8 => return Value.initTag(.manyptr_u8_type),
-            .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type),
-            .manyptr_const_u8_sentinel_0 => return Value.initTag(.manyptr_const_u8_sentinel_0_type),
+            .u1 => return Value{ .ip_index = .u1_type, .legacy = undefined },
+            .u8 => return Value{ .ip_index = .u8_type, .legacy = undefined },
+            .i8 => return Value{ .ip_index = .i8_type, .legacy = undefined },
+            .u16 => return Value{ .ip_index = .u16_type, .legacy = undefined },
+            .u29 => return Value{ .ip_index = .u29_type, .legacy = undefined },
+            .i16 => return Value{ .ip_index = .i16_type, .legacy = undefined },
+            .u32 => return Value{ .ip_index = .u32_type, .legacy = undefined },
+            .i32 => return Value{ .ip_index = .i32_type, .legacy = undefined },
+            .u64 => return Value{ .ip_index = .u64_type, .legacy = undefined },
+            .i64 => return Value{ .ip_index = .i64_type, .legacy = undefined },
+            .single_const_pointer_to_comptime_int => return Value{ .ip_index = .single_const_pointer_to_comptime_int_type, .legacy = undefined },
+            .const_slice_u8 => return Value{ .ip_index = .const_slice_u8_type, .legacy = undefined },
+            .const_slice_u8_sentinel_0 => return Value{ .ip_index = .const_slice_u8_sentinel_0_type, .legacy = undefined },
+            .manyptr_u8 => return Value{ .ip_index = .manyptr_u8_type, .legacy = undefined },
+            .manyptr_const_u8 => return Value{ .ip_index = .manyptr_const_u8_type, .legacy = undefined },
+            .manyptr_const_u8_sentinel_0 => return Value{ .ip_index = .manyptr_const_u8_sentinel_0_type, .legacy = undefined },
             .inferred_alloc_const => unreachable,
             .inferred_alloc_mut => unreachable,
             else => return Value.Tag.ty.create(allocator, self),
src/TypedValue.zig
@@ -77,66 +77,14 @@ pub fn print(
         return writer.writeAll("(variable)");
 
     while (true) switch (val.tag()) {
-        .u1_type => return writer.writeAll("u1"),
-        .u8_type => return writer.writeAll("u8"),
-        .i8_type => return writer.writeAll("i8"),
-        .u16_type => return writer.writeAll("u16"),
-        .i16_type => return writer.writeAll("i16"),
-        .u29_type => return writer.writeAll("u29"),
-        .u32_type => return writer.writeAll("u32"),
-        .i32_type => return writer.writeAll("i32"),
-        .u64_type => return writer.writeAll("u64"),
-        .i64_type => return writer.writeAll("i64"),
-        .u128_type => return writer.writeAll("u128"),
-        .i128_type => return writer.writeAll("i128"),
-        .isize_type => return writer.writeAll("isize"),
-        .usize_type => return writer.writeAll("usize"),
-        .c_char_type => return writer.writeAll("c_char"),
-        .c_short_type => return writer.writeAll("c_short"),
-        .c_ushort_type => return writer.writeAll("c_ushort"),
-        .c_int_type => return writer.writeAll("c_int"),
-        .c_uint_type => return writer.writeAll("c_uint"),
-        .c_long_type => return writer.writeAll("c_long"),
-        .c_ulong_type => return writer.writeAll("c_ulong"),
-        .c_longlong_type => return writer.writeAll("c_longlong"),
-        .c_ulonglong_type => return writer.writeAll("c_ulonglong"),
-        .c_longdouble_type => return writer.writeAll("c_longdouble"),
-        .f16_type => return writer.writeAll("f16"),
-        .f32_type => return writer.writeAll("f32"),
-        .f64_type => return writer.writeAll("f64"),
-        .f80_type => return writer.writeAll("f80"),
-        .f128_type => return writer.writeAll("f128"),
-        .anyopaque_type => return writer.writeAll("anyopaque"),
-        .bool_type => return writer.writeAll("bool"),
-        .void_type => return writer.writeAll("void"),
-        .type_type => return writer.writeAll("type"),
-        .anyerror_type => return writer.writeAll("anyerror"),
-        .comptime_int_type => return writer.writeAll("comptime_int"),
-        .comptime_float_type => return writer.writeAll("comptime_float"),
-        .noreturn_type => return writer.writeAll("noreturn"),
-        .null_type => return writer.writeAll("@Type(.Null)"),
-        .undefined_type => return writer.writeAll("@Type(.Undefined)"),
         .single_const_pointer_to_comptime_int_type => return writer.writeAll("*const comptime_int"),
-        .anyframe_type => return writer.writeAll("anyframe"),
         .const_slice_u8_type => return writer.writeAll("[]const u8"),
         .const_slice_u8_sentinel_0_type => return writer.writeAll("[:0]const u8"),
         .anyerror_void_error_union_type => return writer.writeAll("anyerror!void"),
 
-        .enum_literal_type => return writer.writeAll("@Type(.EnumLiteral)"),
         .manyptr_u8_type => return writer.writeAll("[*]u8"),
         .manyptr_const_u8_type => return writer.writeAll("[*]const u8"),
         .manyptr_const_u8_sentinel_0_type => return writer.writeAll("[*:0]const u8"),
-        .atomic_order_type => return writer.writeAll("std.builtin.AtomicOrder"),
-        .atomic_rmw_op_type => return writer.writeAll("std.builtin.AtomicRmwOp"),
-        .calling_convention_type => return writer.writeAll("std.builtin.CallingConvention"),
-        .address_space_type => return writer.writeAll("std.builtin.AddressSpace"),
-        .float_mode_type => return writer.writeAll("std.builtin.FloatMode"),
-        .reduce_op_type => return writer.writeAll("std.builtin.ReduceOp"),
-        .modifier_type => return writer.writeAll("std.builtin.CallModifier"),
-        .prefetch_options_type => return writer.writeAll("std.builtin.PrefetchOptions"),
-        .export_options_type => return writer.writeAll("std.builtin.ExportOptions"),
-        .extern_options_type => return writer.writeAll("std.builtin.ExternOptions"),
-        .type_info_type => return writer.writeAll("std.builtin.Type"),
 
         .empty_struct_value, .aggregate => {
             if (level == 0) {
@@ -221,11 +169,8 @@ pub fn print(
         .undef => return writer.writeAll("undefined"),
         .zero => return writer.writeAll("0"),
         .one => return writer.writeAll("1"),
-        .void_value => return writer.writeAll("{}"),
         .unreachable_value => return writer.writeAll("unreachable"),
         .the_only_possible_value => return writer.writeAll("0"),
-        .bool_true => return writer.writeAll("true"),
-        .bool_false => return writer.writeAll("false"),
         .ty => return val.castTag(.ty).?.data.print(writer, mod),
         .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer),
         .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer),
@@ -487,8 +432,6 @@ pub fn print(
         // TODO these should not appear in this function
         .inferred_alloc => return writer.writeAll("(inferred allocation value)"),
         .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
-        .generic_poison_type => return writer.writeAll("(generic poison type)"),
-        .generic_poison => return writer.writeAll("(generic poison)"),
         .runtime_value => return writer.writeAll("[runtime value]"),
     };
 }
src/value.zig
@@ -33,58 +33,6 @@ pub const Value = struct {
     // Keep in sync with tools/stage2_pretty_printers_common.py
     pub const Tag = enum(usize) {
         // The first section of this enum are tags that require no payload.
-        u1_type,
-        u8_type,
-        i8_type,
-        u16_type,
-        i16_type,
-        u29_type,
-        u32_type,
-        i32_type,
-        u64_type,
-        i64_type,
-        u128_type,
-        i128_type,
-        usize_type,
-        isize_type,
-        c_char_type,
-        c_short_type,
-        c_ushort_type,
-        c_int_type,
-        c_uint_type,
-        c_long_type,
-        c_ulong_type,
-        c_longlong_type,
-        c_ulonglong_type,
-        c_longdouble_type,
-        f16_type,
-        f32_type,
-        f64_type,
-        f80_type,
-        f128_type,
-        anyopaque_type,
-        bool_type,
-        void_type,
-        type_type,
-        anyerror_type,
-        comptime_int_type,
-        comptime_float_type,
-        noreturn_type,
-        anyframe_type,
-        null_type,
-        undefined_type,
-        enum_literal_type,
-        atomic_order_type,
-        atomic_rmw_op_type,
-        calling_convention_type,
-        address_space_type,
-        float_mode_type,
-        reduce_op_type,
-        modifier_type,
-        prefetch_options_type,
-        export_options_type,
-        extern_options_type,
-        type_info_type,
         manyptr_u8_type,
         manyptr_const_u8_type,
         manyptr_const_u8_sentinel_0_type,
@@ -92,19 +40,14 @@ pub const Value = struct {
         const_slice_u8_type,
         const_slice_u8_sentinel_0_type,
         anyerror_void_error_union_type,
-        generic_poison_type,
 
         undef,
         zero,
         one,
-        void_value,
         unreachable_value,
         /// The only possible value for a particular type, which is stored externally.
         the_only_possible_value,
         null_value,
-        bool_true,
-        bool_false,
-        generic_poison,
 
         empty_struct_value,
         empty_array, // See last_no_payload_tag below.
@@ -197,78 +140,22 @@ pub const Value = struct {
 
         pub fn Type(comptime t: Tag) type {
             return switch (t) {
-                .u1_type,
-                .u8_type,
-                .i8_type,
-                .u16_type,
-                .i16_type,
-                .u29_type,
-                .u32_type,
-                .i32_type,
-                .u64_type,
-                .i64_type,
-                .u128_type,
-                .i128_type,
-                .usize_type,
-                .isize_type,
-                .c_char_type,
-                .c_short_type,
-                .c_ushort_type,
-                .c_int_type,
-                .c_uint_type,
-                .c_long_type,
-                .c_ulong_type,
-                .c_longlong_type,
-                .c_ulonglong_type,
-                .c_longdouble_type,
-                .f16_type,
-                .f32_type,
-                .f64_type,
-                .f80_type,
-                .f128_type,
-                .anyopaque_type,
-                .bool_type,
-                .void_type,
-                .type_type,
-                .anyerror_type,
-                .comptime_int_type,
-                .comptime_float_type,
-                .noreturn_type,
-                .null_type,
-                .undefined_type,
                 .single_const_pointer_to_comptime_int_type,
-                .anyframe_type,
                 .const_slice_u8_type,
                 .const_slice_u8_sentinel_0_type,
                 .anyerror_void_error_union_type,
-                .generic_poison_type,
-                .enum_literal_type,
+
                 .undef,
                 .zero,
                 .one,
-                .void_value,
                 .unreachable_value,
                 .the_only_possible_value,
                 .empty_struct_value,
                 .empty_array,
                 .null_value,
-                .bool_true,
-                .bool_false,
                 .manyptr_u8_type,
                 .manyptr_const_u8_type,
                 .manyptr_const_u8_sentinel_0_type,
-                .atomic_order_type,
-                .atomic_rmw_op_type,
-                .calling_convention_type,
-                .address_space_type,
-                .float_mode_type,
-                .reduce_op_type,
-                .modifier_type,
-                .prefetch_options_type,
-                .export_options_type,
-                .extern_options_type,
-                .type_info_type,
-                .generic_poison,
                 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
 
                 .int_big_positive,
@@ -418,78 +305,22 @@ pub const Value = struct {
                 .legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough },
             };
         } else switch (self.legacy.ptr_otherwise.tag) {
-            .u1_type,
-            .u8_type,
-            .i8_type,
-            .u16_type,
-            .i16_type,
-            .u29_type,
-            .u32_type,
-            .i32_type,
-            .u64_type,
-            .i64_type,
-            .u128_type,
-            .i128_type,
-            .usize_type,
-            .isize_type,
-            .c_char_type,
-            .c_short_type,
-            .c_ushort_type,
-            .c_int_type,
-            .c_uint_type,
-            .c_long_type,
-            .c_ulong_type,
-            .c_longlong_type,
-            .c_ulonglong_type,
-            .c_longdouble_type,
-            .f16_type,
-            .f32_type,
-            .f64_type,
-            .f80_type,
-            .f128_type,
-            .anyopaque_type,
-            .bool_type,
-            .void_type,
-            .type_type,
-            .anyerror_type,
-            .comptime_int_type,
-            .comptime_float_type,
-            .noreturn_type,
-            .null_type,
-            .undefined_type,
             .single_const_pointer_to_comptime_int_type,
-            .anyframe_type,
             .const_slice_u8_type,
             .const_slice_u8_sentinel_0_type,
             .anyerror_void_error_union_type,
-            .generic_poison_type,
-            .enum_literal_type,
+
             .undef,
             .zero,
             .one,
-            .void_value,
             .unreachable_value,
             .the_only_possible_value,
             .empty_array,
             .null_value,
-            .bool_true,
-            .bool_false,
             .empty_struct_value,
             .manyptr_u8_type,
             .manyptr_const_u8_type,
             .manyptr_const_u8_sentinel_0_type,
-            .atomic_order_type,
-            .atomic_rmw_op_type,
-            .calling_convention_type,
-            .address_space_type,
-            .float_mode_type,
-            .reduce_op_type,
-            .modifier_type,
-            .prefetch_options_type,
-            .export_options_type,
-            .extern_options_type,
-            .type_info_type,
-            .generic_poison,
             => unreachable,
 
             .ty, .lazy_align, .lazy_size => {
@@ -722,67 +553,13 @@ pub const Value = struct {
         }
         var val = start_val;
         while (true) switch (val.tag()) {
-            .u1_type => return out_stream.writeAll("u1"),
-            .u8_type => return out_stream.writeAll("u8"),
-            .i8_type => return out_stream.writeAll("i8"),
-            .u16_type => return out_stream.writeAll("u16"),
-            .u29_type => return out_stream.writeAll("u29"),
-            .i16_type => return out_stream.writeAll("i16"),
-            .u32_type => return out_stream.writeAll("u32"),
-            .i32_type => return out_stream.writeAll("i32"),
-            .u64_type => return out_stream.writeAll("u64"),
-            .i64_type => return out_stream.writeAll("i64"),
-            .u128_type => return out_stream.writeAll("u128"),
-            .i128_type => return out_stream.writeAll("i128"),
-            .isize_type => return out_stream.writeAll("isize"),
-            .usize_type => return out_stream.writeAll("usize"),
-            .c_char_type => return out_stream.writeAll("c_char"),
-            .c_short_type => return out_stream.writeAll("c_short"),
-            .c_ushort_type => return out_stream.writeAll("c_ushort"),
-            .c_int_type => return out_stream.writeAll("c_int"),
-            .c_uint_type => return out_stream.writeAll("c_uint"),
-            .c_long_type => return out_stream.writeAll("c_long"),
-            .c_ulong_type => return out_stream.writeAll("c_ulong"),
-            .c_longlong_type => return out_stream.writeAll("c_longlong"),
-            .c_ulonglong_type => return out_stream.writeAll("c_ulonglong"),
-            .c_longdouble_type => return out_stream.writeAll("c_longdouble"),
-            .f16_type => return out_stream.writeAll("f16"),
-            .f32_type => return out_stream.writeAll("f32"),
-            .f64_type => return out_stream.writeAll("f64"),
-            .f80_type => return out_stream.writeAll("f80"),
-            .f128_type => return out_stream.writeAll("f128"),
-            .anyopaque_type => return out_stream.writeAll("anyopaque"),
-            .bool_type => return out_stream.writeAll("bool"),
-            .void_type => return out_stream.writeAll("void"),
-            .type_type => return out_stream.writeAll("type"),
-            .anyerror_type => return out_stream.writeAll("anyerror"),
-            .comptime_int_type => return out_stream.writeAll("comptime_int"),
-            .comptime_float_type => return out_stream.writeAll("comptime_float"),
-            .noreturn_type => return out_stream.writeAll("noreturn"),
-            .null_type => return out_stream.writeAll("@Type(.Null)"),
-            .undefined_type => return out_stream.writeAll("@Type(.Undefined)"),
             .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
-            .anyframe_type => return out_stream.writeAll("anyframe"),
             .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
             .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"),
             .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),
-            .generic_poison_type => return out_stream.writeAll("(generic poison type)"),
-            .generic_poison => return out_stream.writeAll("(generic poison)"),
-            .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
             .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
             .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
             .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"),
-            .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
-            .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
-            .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
-            .address_space_type => return out_stream.writeAll("std.builtin.AddressSpace"),
-            .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"),
-            .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"),
-            .modifier_type => return out_stream.writeAll("std.builtin.CallModifier"),
-            .prefetch_options_type => return out_stream.writeAll("std.builtin.PrefetchOptions"),
-            .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"),
-            .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"),
-            .type_info_type => return out_stream.writeAll("std.builtin.Type"),
 
             .empty_struct_value => return out_stream.writeAll("struct {}{}"),
             .aggregate => {
@@ -795,11 +572,8 @@ pub const Value = struct {
             .undef => return out_stream.writeAll("undefined"),
             .zero => return out_stream.writeAll("0"),
             .one => return out_stream.writeAll("1"),
-            .void_value => return out_stream.writeAll("{}"),
             .unreachable_value => return out_stream.writeAll("unreachable"),
             .the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
-            .bool_true => return out_stream.writeAll("true"),
-            .bool_false => return out_stream.writeAll("false"),
             .ty => return val.castTag(.ty).?.data.dump("", options, out_stream),
             .lazy_align => {
                 try out_stream.writeAll("@alignOf(");
@@ -943,74 +717,16 @@ pub const Value = struct {
 
     /// Asserts that the value is representable as a type.
     pub fn toType(self: Value) Type {
-        if (self.ip_index != .none) {
-            return .{
-                .ip_index = self.ip_index,
-                .legacy = undefined,
-            };
-        }
+        if (self.ip_index != .none) return self.ip_index.toType();
         return switch (self.tag()) {
             .ty => self.castTag(.ty).?.data,
-            .u1_type => Type.u1,
-            .u8_type => Type.u8,
-            .i8_type => Type.i8,
-            .u16_type => Type.u16,
-            .i16_type => Type.i16,
-            .u29_type => Type.u29,
-            .u32_type => Type.u32,
-            .i32_type => Type.i32,
-            .u64_type => Type.u64,
-            .i64_type => Type.i64,
-            .u128_type => Type.u128,
-            .i128_type => Type.i128,
-            .usize_type => Type.usize,
-            .isize_type => Type.isize,
-            .c_char_type => Type.c_char,
-            .c_short_type => Type.c_short,
-            .c_ushort_type => Type.c_ushort,
-            .c_int_type => Type.c_int,
-            .c_uint_type => Type.c_uint,
-            .c_long_type => Type.c_long,
-            .c_ulong_type => Type.c_ulong,
-            .c_longlong_type => Type.c_longlong,
-            .c_ulonglong_type => Type.c_ulonglong,
-            .c_longdouble_type => Type.c_longdouble,
-            .f16_type => Type.f16,
-            .f32_type => Type.f32,
-            .f64_type => Type.f64,
-            .f80_type => Type.f80,
-            .f128_type => Type.f128,
-            .anyopaque_type => Type.anyopaque,
-            .bool_type => Type.bool,
-            .void_type => Type.void,
-            .type_type => Type.type,
-            .anyerror_type => Type.anyerror,
-            .comptime_int_type => Type.comptime_int,
-            .comptime_float_type => Type.comptime_float,
-            .noreturn_type => Type.noreturn,
-            .null_type => Type.null,
-            .undefined_type => Type.undefined,
             .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
-            .anyframe_type => Type.@"anyframe",
             .const_slice_u8_type => Type.initTag(.const_slice_u8),
             .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0),
             .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),
-            .generic_poison_type => .{ .ip_index = .generic_poison_type, .legacy = undefined },
-            .enum_literal_type => .{ .ip_index = .enum_literal_type, .legacy = undefined },
             .manyptr_u8_type => Type.initTag(.manyptr_u8),
             .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
             .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0),
-            .atomic_order_type => .{ .ip_index = .atomic_order_type, .legacy = undefined },
-            .atomic_rmw_op_type => .{ .ip_index = .atomic_rmw_op_type, .legacy = undefined },
-            .calling_convention_type => .{ .ip_index = .calling_convention_type, .legacy = undefined },
-            .address_space_type => .{ .ip_index = .address_space_type, .legacy = undefined },
-            .float_mode_type => .{ .ip_index = .float_mode_type, .legacy = undefined },
-            .reduce_op_type => .{ .ip_index = .reduce_op_type, .legacy = undefined },
-            .modifier_type => .{ .ip_index = .call_modifier_type, .legacy = undefined },
-            .prefetch_options_type => .{ .ip_index = .prefetch_options_type, .legacy = undefined },
-            .export_options_type => .{ .ip_index = .export_options_type, .legacy = undefined },
-            .extern_options_type => .{ .ip_index = .extern_options_type, .legacy = undefined },
-            .type_info_type => .{ .ip_index = .type_info_type, .legacy = undefined },
 
             else => unreachable,
         };
@@ -1133,58 +849,63 @@ pub const Value = struct {
         mod: *const Module,
         opt_sema: ?*Sema,
     ) Module.CompileError!BigIntConst {
-        switch (val.tag()) {
-            .null_value,
-            .zero,
-            .bool_false,
-            .the_only_possible_value, // i0, u0
-            => return BigIntMutable.init(&space.limbs, 0).toConst(),
+        switch (val.ip_index) {
+            .bool_false => return BigIntMutable.init(&space.limbs, 0).toConst(),
+            .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(),
+            .none => switch (val.tag()) {
+                .null_value,
+                .zero,
+                .the_only_possible_value, // i0, u0
+                => return BigIntMutable.init(&space.limbs, 0).toConst(),
 
-            .one,
-            .bool_true,
-            => return BigIntMutable.init(&space.limbs, 1).toConst(),
+                .one => return BigIntMutable.init(&space.limbs, 1).toConst(),
 
-            .enum_field_index => {
-                const index = val.castTag(.enum_field_index).?.data;
-                return BigIntMutable.init(&space.limbs, index).toConst();
-            },
-            .runtime_value => {
-                const sub_val = val.castTag(.runtime_value).?.data;
-                return sub_val.toBigIntAdvanced(space, mod, opt_sema);
-            },
-            .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(),
-            .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(),
-            .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
-            .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
+                .enum_field_index => {
+                    const index = val.castTag(.enum_field_index).?.data;
+                    return BigIntMutable.init(&space.limbs, index).toConst();
+                },
+                .runtime_value => {
+                    const sub_val = val.castTag(.runtime_value).?.data;
+                    return sub_val.toBigIntAdvanced(space, mod, opt_sema);
+                },
+                .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(),
+                .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(),
+                .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
+                .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
 
-            .undef => unreachable,
+                .undef => unreachable,
 
-            .lazy_align => {
-                const ty = val.castTag(.lazy_align).?.data;
-                if (opt_sema) |sema| {
-                    try sema.resolveTypeLayout(ty);
-                }
-                const x = ty.abiAlignment(mod);
-                return BigIntMutable.init(&space.limbs, x).toConst();
-            },
-            .lazy_size => {
-                const ty = val.castTag(.lazy_size).?.data;
-                if (opt_sema) |sema| {
-                    try sema.resolveTypeLayout(ty);
-                }
-                const x = ty.abiSize(mod);
-                return BigIntMutable.init(&space.limbs, x).toConst();
-            },
+                .lazy_align => {
+                    const ty = val.castTag(.lazy_align).?.data;
+                    if (opt_sema) |sema| {
+                        try sema.resolveTypeLayout(ty);
+                    }
+                    const x = ty.abiAlignment(mod);
+                    return BigIntMutable.init(&space.limbs, x).toConst();
+                },
+                .lazy_size => {
+                    const ty = val.castTag(.lazy_size).?.data;
+                    if (opt_sema) |sema| {
+                        try sema.resolveTypeLayout(ty);
+                    }
+                    const x = ty.abiSize(mod);
+                    return BigIntMutable.init(&space.limbs, x).toConst();
+                },
 
-            .elem_ptr => {
-                const elem_ptr = val.castTag(.elem_ptr).?.data;
-                const array_addr = (try elem_ptr.array_ptr.getUnsignedIntAdvanced(mod, opt_sema)).?;
-                const elem_size = elem_ptr.elem_ty.abiSize(mod);
-                const new_addr = array_addr + elem_size * elem_ptr.index;
-                return BigIntMutable.init(&space.limbs, new_addr).toConst();
-            },
+                .elem_ptr => {
+                    const elem_ptr = val.castTag(.elem_ptr).?.data;
+                    const array_addr = (try elem_ptr.array_ptr.getUnsignedIntAdvanced(mod, opt_sema)).?;
+                    const elem_size = elem_ptr.elem_ty.abiSize(mod);
+                    const new_addr = array_addr + elem_size * elem_ptr.index;
+                    return BigIntMutable.init(&space.limbs, new_addr).toConst();
+                },
 
-            else => unreachable,
+                else => unreachable,
+            },
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return int.big_int,
+                else => unreachable,
+            },
         }
     }
 
@@ -1197,41 +918,46 @@ pub const Value = struct {
     /// If the value fits in a u64, return it, otherwise null.
     /// Asserts not undefined.
     pub fn getUnsignedIntAdvanced(val: Value, mod: *const Module, opt_sema: ?*Sema) !?u64 {
-        switch (val.tag()) {
-            .zero,
-            .bool_false,
-            .the_only_possible_value, // i0, u0
-            => return 0,
+        switch (val.ip_index) {
+            .bool_false => return 0,
+            .bool_true => return 1,
+            .none => switch (val.tag()) {
+                .zero,
+                .the_only_possible_value, // i0, u0
+                => return 0,
 
-            .one,
-            .bool_true,
-            => return 1,
+                .one => return 1,
 
-            .int_u64 => return val.castTag(.int_u64).?.data,
-            .int_i64 => return @intCast(u64, val.castTag(.int_i64).?.data),
-            .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
-            .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
+                .int_u64 => return val.castTag(.int_u64).?.data,
+                .int_i64 => return @intCast(u64, val.castTag(.int_i64).?.data),
+                .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
+                .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
 
-            .undef => unreachable,
+                .undef => unreachable,
 
-            .lazy_align => {
-                const ty = val.castTag(.lazy_align).?.data;
-                if (opt_sema) |sema| {
-                    return (try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
-                } else {
-                    return ty.abiAlignment(mod);
-                }
+                .lazy_align => {
+                    const ty = val.castTag(.lazy_align).?.data;
+                    if (opt_sema) |sema| {
+                        return (try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
+                    } else {
+                        return ty.abiAlignment(mod);
+                    }
+                },
+                .lazy_size => {
+                    const ty = val.castTag(.lazy_size).?.data;
+                    if (opt_sema) |sema| {
+                        return (try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
+                    } else {
+                        return ty.abiSize(mod);
+                    }
+                },
+
+                else => return null,
             },
-            .lazy_size => {
-                const ty = val.castTag(.lazy_size).?.data;
-                if (opt_sema) |sema| {
-                    return (try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
-                } else {
-                    return ty.abiSize(mod);
-                }
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return int.big_int.to(u64) catch null,
+                else => unreachable,
             },
-
-            else => return null,
         }
     }
 
@@ -1242,51 +968,65 @@ pub const Value = struct {
 
     /// Asserts the value is an integer and it fits in a i64
     pub fn toSignedInt(val: Value, mod: *const Module) i64 {
-        switch (val.tag()) {
-            .zero,
-            .bool_false,
-            .the_only_possible_value, // i0, u0
-            => return 0,
+        switch (val.ip_index) {
+            .bool_false => return 0,
+            .bool_true => return 1,
+            .none => switch (val.tag()) {
+                .zero,
+                .the_only_possible_value, // i0, u0
+                => return 0,
 
-            .one,
-            .bool_true,
-            => return 1,
+                .one => return 1,
 
-            .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data),
-            .int_i64 => return val.castTag(.int_i64).?.data,
-            .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
-            .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
+                .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data),
+                .int_i64 => return val.castTag(.int_i64).?.data,
+                .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
+                .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
 
-            .lazy_align => {
-                const ty = val.castTag(.lazy_align).?.data;
-                return @intCast(i64, ty.abiAlignment(mod));
+                .lazy_align => {
+                    const ty = val.castTag(.lazy_align).?.data;
+                    return @intCast(i64, ty.abiAlignment(mod));
+                },
+                .lazy_size => {
+                    const ty = val.castTag(.lazy_size).?.data;
+                    return @intCast(i64, ty.abiSize(mod));
+                },
+
+                .undef => unreachable,
+                else => unreachable,
             },
-            .lazy_size => {
-                const ty = val.castTag(.lazy_size).?.data;
-                return @intCast(i64, ty.abiSize(mod));
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return int.big_int.to(i64) catch unreachable,
+                else => unreachable,
             },
-
-            .undef => unreachable,
-            else => unreachable,
         }
     }
 
-    pub fn toBool(self: Value) bool {
-        return switch (self.tag()) {
-            .bool_true, .one => true,
-            .bool_false, .zero => false,
-            .int_u64 => switch (self.castTag(.int_u64).?.data) {
-                0 => false,
-                1 => true,
+    pub fn toBool(val: Value, mod: *const Module) bool {
+        switch (val.ip_index) {
+            .bool_true => return true,
+            .bool_false => return false,
+            .none => return switch (val.tag()) {
+                .one => true,
+                .zero => false,
+
+                .int_u64 => switch (val.castTag(.int_u64).?.data) {
+                    0 => false,
+                    1 => true,
+                    else => unreachable,
+                },
+                .int_i64 => switch (val.castTag(.int_i64).?.data) {
+                    0 => false,
+                    1 => true,
+                    else => unreachable,
+                },
                 else => unreachable,
             },
-            .int_i64 => switch (self.castTag(.int_i64).?.data) {
-                0 => false,
-                1 => true,
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return !int.big_int.eqZero(),
                 else => unreachable,
             },
-            else => unreachable,
-        };
+        }
     }
 
     fn isDeclRef(val: Value) bool {
@@ -1319,7 +1059,7 @@ pub const Value = struct {
         switch (ty.zigTypeTag(mod)) {
             .Void => {},
             .Bool => {
-                buffer[0] = @boolToInt(val.toBool());
+                buffer[0] = @boolToInt(val.toBool(mod));
             },
             .Int, .Enum => {
                 const int_info = ty.intInfo(mod);
@@ -1442,7 +1182,7 @@ pub const Value = struct {
                     .Little => bit_offset / 8,
                     .Big => buffer.len - bit_offset / 8 - 1,
                 };
-                if (val.toBool()) {
+                if (val.toBool(mod)) {
                     buffer[byte_index] |= (@as(u8, 1) << @intCast(u3, bit_offset % 8));
                 } else {
                     buffer[byte_index] &= ~(@as(u8, 1) << @intCast(u3, bit_offset % 8));
@@ -1802,90 +1542,117 @@ pub const Value = struct {
 
     pub fn clz(val: Value, ty: Type, mod: *const Module) u64 {
         const ty_bits = ty.intInfo(mod).bits;
-        switch (val.tag()) {
-            .zero, .bool_false => return ty_bits,
-            .one, .bool_true => return ty_bits - 1,
+        switch (val.ip_index) {
+            .bool_false => return ty_bits,
+            .bool_true => return ty_bits - 1,
+            .none => switch (val.tag()) {
+                .zero => return ty_bits,
+                .one => return ty_bits - 1,
+
+                .int_u64 => {
+                    const big = @clz(val.castTag(.int_u64).?.data);
+                    return big + ty_bits - 64;
+                },
+                .int_i64 => {
+                    @panic("TODO implement i64 Value clz");
+                },
+                .int_big_positive => {
+                    const bigint = val.castTag(.int_big_positive).?.asBigInt();
+                    return bigint.clz(ty_bits);
+                },
+                .int_big_negative => {
+                    @panic("TODO implement int_big_negative Value clz");
+                },
 
-            .int_u64 => {
-                const big = @clz(val.castTag(.int_u64).?.data);
-                return big + ty_bits - 64;
-            },
-            .int_i64 => {
-                @panic("TODO implement i64 Value clz");
-            },
-            .int_big_positive => {
-                const bigint = val.castTag(.int_big_positive).?.asBigInt();
-                return bigint.clz(ty_bits);
-            },
-            .int_big_negative => {
-                @panic("TODO implement int_big_negative Value clz");
-            },
+                .the_only_possible_value => {
+                    assert(ty_bits == 0);
+                    return ty_bits;
+                },
 
-            .the_only_possible_value => {
-                assert(ty_bits == 0);
-                return ty_bits;
-            },
+                .lazy_align, .lazy_size => {
+                    var bigint_buf: BigIntSpace = undefined;
+                    const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable;
+                    return bigint.clz(ty_bits);
+                },
 
-            .lazy_align, .lazy_size => {
-                var bigint_buf: BigIntSpace = undefined;
-                const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable;
-                return bigint.clz(ty_bits);
+                else => unreachable,
+            },
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return int.big_int.clz(ty_bits),
+                else => unreachable,
             },
-
-            else => unreachable,
         }
     }
 
     pub fn ctz(val: Value, ty: Type, mod: *const Module) u64 {
         const ty_bits = ty.intInfo(mod).bits;
-        switch (val.tag()) {
-            .zero, .bool_false => return ty_bits,
-            .one, .bool_true => return 0,
+        switch (val.ip_index) {
+            .bool_false => return ty_bits,
+            .bool_true => return 0,
+            .none => switch (val.tag()) {
+                .zero => return ty_bits,
+                .one => return 0,
+
+                .int_u64 => {
+                    const big = @ctz(val.castTag(.int_u64).?.data);
+                    return if (big == 64) ty_bits else big;
+                },
+                .int_i64 => {
+                    @panic("TODO implement i64 Value ctz");
+                },
+                .int_big_positive => {
+                    const bigint = val.castTag(.int_big_positive).?.asBigInt();
+                    return bigint.ctz();
+                },
+                .int_big_negative => {
+                    @panic("TODO implement int_big_negative Value ctz");
+                },
 
-            .int_u64 => {
-                const big = @ctz(val.castTag(.int_u64).?.data);
-                return if (big == 64) ty_bits else big;
-            },
-            .int_i64 => {
-                @panic("TODO implement i64 Value ctz");
-            },
-            .int_big_positive => {
-                const bigint = val.castTag(.int_big_positive).?.asBigInt();
-                return bigint.ctz();
-            },
-            .int_big_negative => {
-                @panic("TODO implement int_big_negative Value ctz");
-            },
+                .the_only_possible_value => {
+                    assert(ty_bits == 0);
+                    return ty_bits;
+                },
 
-            .the_only_possible_value => {
-                assert(ty_bits == 0);
-                return ty_bits;
-            },
+                .lazy_align, .lazy_size => {
+                    var bigint_buf: BigIntSpace = undefined;
+                    const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable;
+                    return bigint.ctz();
+                },
 
-            .lazy_align, .lazy_size => {
-                var bigint_buf: BigIntSpace = undefined;
-                const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable;
-                return bigint.ctz();
+                else => unreachable,
+            },
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| return int.big_int.ctz(),
+                else => unreachable,
             },
-
-            else => unreachable,
         }
     }
 
     pub fn popCount(val: Value, ty: Type, mod: *const Module) u64 {
         assert(!val.isUndef());
-        switch (val.tag()) {
-            .zero, .bool_false => return 0,
-            .one, .bool_true => return 1,
+        switch (val.ip_index) {
+            .bool_false => return 0,
+            .bool_true => return 1,
+            .none => switch (val.tag()) {
+                .zero => return 0,
+                .one => return 1,
 
-            .int_u64 => return @popCount(val.castTag(.int_u64).?.data),
+                .int_u64 => return @popCount(val.castTag(.int_u64).?.data),
 
-            else => {
-                const info = ty.intInfo(mod);
+                else => {
+                    const info = ty.intInfo(mod);
 
-                var buffer: Value.BigIntSpace = undefined;
-                const int = val.toBigInt(&buffer, mod);
-                return @intCast(u64, int.popCount(info.bits));
+                    var buffer: Value.BigIntSpace = undefined;
+                    const int = val.toBigInt(&buffer, mod);
+                    return @intCast(u64, int.popCount(info.bits));
+                },
+            },
+            else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
+                .int => |int| {
+                    const info = ty.intInfo(mod);
+                    return int.big_int.popCount(info.bits);
+                },
+                else => unreachable,
             },
         }
     }
@@ -1933,37 +1700,42 @@ pub const Value = struct {
     /// Returns the number of bits the value requires to represent stored in twos complement form.
     pub fn intBitCountTwosComp(self: Value, mod: *const Module) usize {
         const target = mod.getTarget();
-        switch (self.tag()) {
-            .zero,
-            .bool_false,
-            .the_only_possible_value,
-            => return 0,
-
-            .one,
-            .bool_true,
-            => return 1,
+        switch (self.ip_index) {
+            .bool_false => return 0,
+            .bool_true => return 1,
+            .none => switch (self.tag()) {
+                .zero,
+                .the_only_possible_value,
+                => return 0,
 
-            .int_u64 => {
-                const x = self.castTag(.int_u64).?.data;
-                if (x == 0) return 0;
-                return @intCast(usize, std.math.log2(x) + 1);
-            },
-            .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
-            .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
+                .one => return 1,
 
-            .decl_ref_mut,
-            .comptime_field_ptr,
-            .extern_fn,
-            .decl_ref,
-            .function,
-            .variable,
-            .eu_payload_ptr,
-            .opt_payload_ptr,
-            => return target.ptrBitWidth(),
+                .int_u64 => {
+                    const x = self.castTag(.int_u64).?.data;
+                    if (x == 0) return 0;
+                    return @intCast(usize, std.math.log2(x) + 1);
+                },
+                .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
+                .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
+
+                .decl_ref_mut,
+                .comptime_field_ptr,
+                .extern_fn,
+                .decl_ref,
+                .function,
+                .variable,
+                .eu_payload_ptr,
+                .opt_payload_ptr,
+                => return target.ptrBitWidth(),
 
-            else => {
-                var buffer: BigIntSpace = undefined;
-                return self.toBigInt(&buffer, mod).bitCountTwosComp();
+                else => {
+                    var buffer: BigIntSpace = undefined;
+                    return self.toBigInt(&buffer, mod).bitCountTwosComp();
+                },
+            },
+            else => switch (mod.intern_pool.indexToKey(self.ip_index)) {
+                .int => |int| return int.big_int.bitCountTwosComp(),
+                else => unreachable,
             },
         }
     }
@@ -2008,82 +1780,88 @@ pub const Value = struct {
         mod: *const Module,
         opt_sema: ?*Sema,
     ) Module.CompileError!std.math.Order {
-        return switch (lhs.tag()) {
-            .zero,
-            .bool_false,
-            .the_only_possible_value,
-            => .eq,
+        switch (lhs.ip_index) {
+            .bool_false => return .eq,
+            .bool_true => return .gt,
+            .none => return switch (lhs.tag()) {
+                .zero,
+                .the_only_possible_value,
+                => .eq,
 
-            .one,
-            .bool_true,
-            .decl_ref,
-            .decl_ref_mut,
-            .comptime_field_ptr,
-            .extern_fn,
-            .function,
-            .variable,
-            => .gt,
+                .one,
+                .decl_ref,
+                .decl_ref_mut,
+                .comptime_field_ptr,
+                .extern_fn,
+                .function,
+                .variable,
+                => .gt,
+
+                .enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0),
+                .runtime_value => {
+                    // This is needed to correctly handle hashing the value.
+                    // Checks in Sema should prevent direct comparisons from reaching here.
+                    const val = lhs.castTag(.runtime_value).?.data;
+                    return val.orderAgainstZeroAdvanced(mod, opt_sema);
+                },
+                .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
+                .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
+                .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
+                .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0),
+
+                .lazy_align => {
+                    const ty = lhs.castTag(.lazy_align).?.data;
+                    const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
+                    if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
+                        error.NeedLazy => unreachable,
+                        else => |e| return e,
+                    }) {
+                        return .gt;
+                    } else {
+                        return .eq;
+                    }
+                },
+                .lazy_size => {
+                    const ty = lhs.castTag(.lazy_size).?.data;
+                    const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
+                    if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
+                        error.NeedLazy => unreachable,
+                        else => |e| return e,
+                    }) {
+                        return .gt;
+                    } else {
+                        return .eq;
+                    }
+                },
 
-            .enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0),
-            .runtime_value => {
-                // This is needed to correctly handle hashing the value.
-                // Checks in Sema should prevent direct comparisons from reaching here.
-                const val = lhs.castTag(.runtime_value).?.data;
-                return val.orderAgainstZeroAdvanced(mod, opt_sema);
-            },
-            .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
-            .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
-            .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
-            .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0),
+                .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
+                .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
+                .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
+                .float_80 => std.math.order(lhs.castTag(.float_80).?.data, 0),
+                .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
+
+                .elem_ptr => {
+                    const elem_ptr = lhs.castTag(.elem_ptr).?.data;
+                    switch (try elem_ptr.array_ptr.orderAgainstZeroAdvanced(mod, opt_sema)) {
+                        .lt => unreachable,
+                        .gt => return .gt,
+                        .eq => {
+                            if (elem_ptr.index == 0) {
+                                return .eq;
+                            } else {
+                                return .gt;
+                            }
+                        },
+                    }
+                },
 
-            .lazy_align => {
-                const ty = lhs.castTag(.lazy_align).?.data;
-                const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
-                if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
-                    error.NeedLazy => unreachable,
-                    else => |e| return e,
-                }) {
-                    return .gt;
-                } else {
-                    return .eq;
-                }
-            },
-            .lazy_size => {
-                const ty = lhs.castTag(.lazy_size).?.data;
-                const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
-                if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
-                    error.NeedLazy => unreachable,
-                    else => |e| return e,
-                }) {
-                    return .gt;
-                } else {
-                    return .eq;
-                }
+                else => unreachable,
             },
-
-            .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
-            .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
-            .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
-            .float_80 => std.math.order(lhs.castTag(.float_80).?.data, 0),
-            .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
-
-            .elem_ptr => {
-                const elem_ptr = lhs.castTag(.elem_ptr).?.data;
-                switch (try elem_ptr.array_ptr.orderAgainstZeroAdvanced(mod, opt_sema)) {
-                    .lt => unreachable,
-                    .gt => return .gt,
-                    .eq => {
-                        if (elem_ptr.index == 0) {
-                            return .eq;
-                        } else {
-                            return .gt;
-                        }
-                    },
-                }
+            else => switch (mod.intern_pool.indexToKey(lhs.ip_index)) {
+                .int => |int| return int.big_int.orderAgainstScalar(0),
+                else => unreachable,
             },
-
-            else => unreachable,
-        };
+        }
     }
 
     /// Asserts the value is comparable.
@@ -2293,12 +2071,14 @@ pub const Value = struct {
         mod: *Module,
         opt_sema: ?*Sema,
     ) Module.CompileError!bool {
+        if (a.ip_index != .none or b.ip_index != .none) return a.ip_index == b.ip_index;
+
         const target = mod.getTarget();
         const a_tag = a.tag();
         const b_tag = b.tag();
         if (a_tag == b_tag) switch (a_tag) {
             .undef => return true,
-            .void_value, .null_value, .the_only_possible_value, .empty_struct_value => return true,
+            .null_value, .the_only_possible_value, .empty_struct_value => return true,
             .enum_literal => {
                 const a_name = a.castTag(.enum_literal).?.data;
                 const b_name = b.castTag(.enum_literal).?.data;
@@ -2574,6 +2354,13 @@ pub const Value = struct {
     /// This function is used by hash maps and so treats floating-point NaNs as equal
     /// to each other, and not equal to other floating-point values.
     pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void {
+        if (val.ip_index != .none) {
+            // The InternPool data structure hashes based on Key to make interned objects
+            // unique. An Index can be treated simply as u32 value for the
+            // purpose of Type/Value hashing and equality.
+            std.hash.autoHash(hasher, val.ip_index);
+            return;
+        }
         const zig_ty_tag = ty.zigTypeTag(mod);
         std.hash.autoHash(hasher, zig_ty_tag);
         if (val.isUndef()) return;
@@ -2908,8 +2695,6 @@ pub const Value = struct {
             .int_i64,
             .int_big_positive,
             .int_big_negative,
-            .bool_false,
-            .bool_true,
             .the_only_possible_value,
             .lazy_align,
             .lazy_size,
@@ -3051,15 +2836,6 @@ pub const Value = struct {
             .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
             .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer),
 
-            // These values will implicitly be treated as `repeated`.
-            .zero,
-            .one,
-            .bool_false,
-            .bool_true,
-            .int_i64,
-            .int_u64,
-            => return val,
-
             else => unreachable,
         }
     }
@@ -3272,13 +3048,10 @@ pub const Value = struct {
             // in which case the value 0 is null and other values are non-null.
 
             .zero,
-            .bool_false,
             .the_only_possible_value,
             => true,
 
-            .one,
-            .bool_true,
-            => false,
+            .one => false,
 
             .int_u64,
             .int_i64,
@@ -5419,11 +5192,7 @@ pub const Value = struct {
     }
 
     pub fn isGenericPoison(val: Value) bool {
-        return switch (val.ip_index) {
-            .generic_poison => true,
-            .none => val.tag() == .generic_poison,
-            else => false,
-        };
+        return val.ip_index == .generic_poison;
     }
 
     /// This type is not copyable since it may contain pointers to its inner data.
@@ -5673,10 +5442,13 @@ pub const Value = struct {
         .legacy = .{ .ptr_otherwise = &negative_one_payload.base },
     };
     pub const undef = initTag(.undef);
-    pub const @"void" = initTag(.void_value);
+    pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined };
     pub const @"null" = initTag(.null_value);
-    pub const @"false" = initTag(.bool_false);
-    pub const @"true" = initTag(.bool_true);
+    pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined };
+    pub const @"true": Value = .{ .ip_index = .bool_true, .legacy = undefined };
+
+    pub const generic_poison: Value = .{ .ip_index = .generic_poison, .legacy = undefined };
+    pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined };
 
     pub fn makeBool(x: bool) Value {
         return if (x) Value.true else Value.false;
src/Zir.zig
@@ -2106,8 +2106,10 @@ pub const Inst = struct {
         type_info_type = @enumToInt(InternPool.Index.type_info_type),
         manyptr_u8_type = @enumToInt(InternPool.Index.manyptr_u8_type),
         manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type),
+        manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type),
         single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type),
         const_slice_u8_type = @enumToInt(InternPool.Index.const_slice_u8_type),
+        const_slice_u8_sentinel_0_type = @enumToInt(InternPool.Index.const_slice_u8_sentinel_0_type),
         anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type),
         generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type),
         var_args_param_type = @enumToInt(InternPool.Index.var_args_param_type),
@@ -2115,6 +2117,7 @@ pub const Inst = struct {
         undef = @enumToInt(InternPool.Index.undef),
         zero = @enumToInt(InternPool.Index.zero),
         zero_usize = @enumToInt(InternPool.Index.zero_usize),
+        zero_u8 = @enumToInt(InternPool.Index.zero_u8),
         one = @enumToInt(InternPool.Index.one),
         one_usize = @enumToInt(InternPool.Index.one_usize),
         calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c),