Commit f47dea2a2e

Andrew Kelley <superjoe30@gmail.com>
2016-12-25 10:15:23
IR: support compile time global pointer reinterpret
this required moving the place we store types to ConstExprValue
1 parent 6f91fb4
src/all_types.hpp
@@ -131,6 +131,7 @@ enum RuntimeHintMaybe {
 };
 
 struct ConstExprValue {
+    TypeTableEntry *type;
     ConstValSpecial special;
     bool depends_on_compile_var;
     LLVMValueRef llvm_value;
@@ -429,8 +430,6 @@ enum CastOp {
     CastOpPtrToInt,
     CastOpIntToPtr,
     CastOpWidenOrShorten,
-    CastOpToUnknownSizeArray,
-    CastOpPointerReinterpret,
     CastOpErrToInt,
     CastOpIntToFloat,
     CastOpFloatToInt,
@@ -749,14 +748,9 @@ struct FnTypeParamInfo {
     TypeTableEntry *type;
 };
 
-struct GenericParamValue {
-    TypeTableEntry *type;
-    ConstExprValue *value;
-};
-
 struct GenericFnTypeId {
     FnTableEntry *fn_entry;
-    GenericParamValue *params;
+    ConstExprValue *params;
     size_t param_count;
 };
 
@@ -1238,7 +1232,7 @@ struct CodeGen {
 // TODO after merging IR branch, we can probably delete some of these fields
 struct VariableTableEntry {
     Buf name;
-    TypeTableEntry *type;
+    ConstExprValue value;
     LLVMValueRef value_ref;
     bool src_is_const;
     bool gen_is_const;
@@ -1254,7 +1248,6 @@ struct VariableTableEntry {
     bool shadowable;
     size_t mem_slot_index;
     size_t ref_count;
-    ConstExprValue *value;
     bool is_extern;
 };
 
@@ -1460,14 +1453,14 @@ enum IrInstructionId {
     IrInstructionIdFnProto,
     IrInstructionIdTestComptime,
     IrInstructionIdInitEnum,
+    IrInstructionIdPointerReinterpret,
 };
 
 struct IrInstruction {
     IrInstructionId id;
     Scope *scope;
     AstNode *source_node;
-    ConstExprValue static_value;
-    TypeTableEntry *type_entry;
+    ConstExprValue value;
     size_t debug_id;
     LLVMValueRef llvm_value;
     // if ref_count is zero, instruction can be omitted in codegen
@@ -1986,6 +1979,7 @@ struct IrInstructionSlice {
     IrInstruction *start;
     IrInstruction *end;
     bool is_const;
+    bool safety_check_on;
     LLVMValueRef tmp_ptr;
 };
 
@@ -2096,6 +2090,12 @@ struct IrInstructionInitEnum {
     LLVMValueRef tmp_ptr;
 };
 
+struct IrInstructionPointerReinterpret {
+    IrInstruction base;
+
+    IrInstruction *ptr;
+};
+
 enum LValPurpose {
     LValPurposeNone,
     LValPurposeAssign,
src/analyze.cpp
@@ -876,11 +876,11 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
 
 TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
     IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
-    if (result->type_entry->id == TypeTableEntryIdInvalid)
+    if (result->value.type->id == TypeTableEntryIdInvalid)
         return g->builtin_types.entry_invalid;
 
-    assert(result->static_value.special != ConstValSpecialRuntime);
-    return result->static_value.data.x_type;
+    assert(result->value.special != ConstValSpecialRuntime);
+    return result->value.data.x_type;
 }
 
 static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
@@ -1708,41 +1708,42 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
 // Set name to nullptr to make the variable anonymous (not visible to programmer).
 // TODO merge with definition of add_local_var in ir.cpp
 VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
-    TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value)
+    bool is_const, ConstExprValue *value)
 {
+    assert(value);
+
     VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
-    variable_entry->type = type_entry;
+    variable_entry->value = *value;
     variable_entry->parent_scope = parent_scope;
     variable_entry->shadowable = false;
     variable_entry->mem_slot_index = SIZE_MAX;
-    variable_entry->value = init_value;
     variable_entry->src_arg_index = SIZE_MAX;
 
     assert(name);
 
     buf_init_from_buf(&variable_entry->name, name);
 
-    if (type_entry->id != TypeTableEntryIdInvalid) {
+    if (value->type->id != TypeTableEntryIdInvalid) {
         VariableTableEntry *existing_var = find_variable(g, parent_scope, name);
         if (existing_var && !existing_var->shadowable) {
             ErrorMsg *msg = add_node_error(g, source_node,
                     buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
             add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
-            variable_entry->type = g->builtin_types.entry_invalid;
+            variable_entry->value.type = g->builtin_types.entry_invalid;
         } else {
             auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
             if (primitive_table_entry) {
                 TypeTableEntry *type = primitive_table_entry->value;
                 add_node_error(g, source_node,
                         buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
-                variable_entry->type = g->builtin_types.entry_invalid;
+                variable_entry->value.type = g->builtin_types.entry_invalid;
             } else {
                 Tld *tld = find_decl(parent_scope, name);
                 if (tld && tld->id != TldIdVar) {
                     ErrorMsg *msg = add_node_error(g, source_node,
                             buf_sprintf("redefinition of '%s'", buf_ptr(name)));
                     add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
-                    variable_entry->type = g->builtin_types.entry_invalid;
+                    variable_entry->value.type = g->builtin_types.entry_invalid;
                 }
             }
         }
@@ -1789,7 +1790,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     } else if (var_decl->expr) {
         init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
         assert(init_value);
-        implicit_type = init_value->type_entry;
+        implicit_type = init_value->value.type;
 
         if (implicit_type->id == TypeTableEntryIdUnreachable) {
             add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
@@ -1807,7 +1808,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
             add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
             implicit_type = g->builtin_types.entry_invalid;
         }
-        assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->static_value.special != ConstValSpecialRuntime);
+        assert(implicit_type->id == TypeTableEntryIdInvalid || init_value->value.special != ConstValSpecialRuntime);
     } else if (!is_extern) {
         add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
         implicit_type = g->builtin_types.entry_invalid;
@@ -1816,8 +1817,9 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
     TypeTableEntry *type = explicit_type ? explicit_type : implicit_type;
     assert(type != nullptr); // should have been caught by the parser
 
-    tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope,
-            var_decl->symbol, type, is_const, &init_value->static_value);
+    ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
+
+    tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, is_const, init_val);
     tld_var->var->is_extern = is_extern;
 
     g->global_vars.append(tld_var->var);
@@ -2231,7 +2233,8 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
                 buf_sprintf("byvalue types not yet supported on extern function parameters"));
         }
 
-        VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, param_decl->name, param_type, true, nullptr);
+        VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
+                param_decl->name, true, create_const_runtime(param_type));
         var->src_arg_index = i;
         fn_table_entry->child_scope = var->child_scope;
 
@@ -2287,14 +2290,14 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
 
 static void add_symbols_from_import(CodeGen *g, AstNode *dst_use_node) {
     IrInstruction *use_target_value = dst_use_node->data.use.value;
-    if (use_target_value->type_entry->id == TypeTableEntryIdInvalid) {
+    if (use_target_value->value.type->id == TypeTableEntryIdInvalid) {
         dst_use_node->owner->any_imports_failed = true;
         return;
     }
 
     dst_use_node->data.use.resolution = TldResolutionOk;
 
-    ConstExprValue *const_val = &use_target_value->static_value;
+    ConstExprValue *const_val = &use_target_value->value;
     assert(const_val->special != ConstValSpecialRuntime);
 
     ImportTableEntry *target_import = const_val->data.x_import;
@@ -2351,7 +2354,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
     IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
         node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
 
-    if (result->type_entry->id == TypeTableEntryIdInvalid)
+    if (result->value.type->id == TypeTableEntryIdInvalid)
         node->owner->any_imports_failed = true;
 
     node->data.use.value = result;
@@ -2620,8 +2623,9 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
     return true;
 }
 
-static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) {
-    switch (type->id) {
+static uint32_t hash_const_val(ConstExprValue *const_val) {
+    assert(const_val->special == ConstValSpecialStatic);
+    switch (const_val->type->id) {
         case TypeTableEntryIdBool:
             return const_val->data.x_bool ? 127863866 : 215080464;
         case TypeTableEntryIdMetaType:
@@ -2630,6 +2634,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
             return 4149439618;
         case TypeTableEntryIdInt:
         case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdEnumTag:
             return ((uint32_t)(bignum_to_twos_complement(&const_val->data.x_bignum) % UINT32_MAX)) * 1331471175;
         case TypeTableEntryIdFloat:
         case TypeTableEntryIdNumLitFloat:
@@ -2651,8 +2656,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
             return 2709806591;
         case TypeTableEntryIdMaybe:
             if (const_val->data.x_maybe) {
-                TypeTableEntry *child_type = type->data.maybe.child_type;
-                return hash_const_val(child_type, const_val->data.x_maybe) * 1992916303;
+                return hash_const_val(const_val->data.x_maybe) * 1992916303;
             } else {
                 return 4016830364;
             }
@@ -2673,8 +2677,6 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
             return hash_ptr(const_val->data.x_import);
         case TypeTableEntryIdBlock:
             return hash_ptr(const_val->data.x_block);
-        case TypeTableEntryIdEnumTag:
-            return 983996406 + hash_const_val(type->data.enum_tag.int_type, const_val);
         case TypeTableEntryIdBoundFn:
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdUnreachable:
@@ -2688,9 +2690,9 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {
     uint32_t result = 0;
     result += hash_ptr(id->fn_entry);
     for (size_t i = 0; i < id->param_count; i += 1) {
-        GenericParamValue *generic_param = &id->params[i];
-        if (generic_param->value) {
-            result += hash_const_val(generic_param->type, generic_param->value);
+        ConstExprValue *generic_param = &id->params[i];
+        if (generic_param->special != ConstValSpecialRuntime) {
+            result += hash_const_val(generic_param);
             result += hash_ptr(generic_param->type);
         }
     }
@@ -2702,17 +2704,17 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
     if (a->fn_entry != b->fn_entry) return false;
     assert(a->param_count == b->param_count);
     for (size_t i = 0; i < a->param_count; i += 1) {
-        GenericParamValue *a_val = &a->params[i];
-        GenericParamValue *b_val = &b->params[i];
+        ConstExprValue *a_val = &a->params[i];
+        ConstExprValue *b_val = &b->params[i];
         if (a_val->type != b_val->type) return false;
-        if (a_val->value && b_val->value) {
-            assert(a_val->value->special == ConstValSpecialStatic);
-            assert(b_val->value->special == ConstValSpecialStatic);
-            if (!const_values_equal(a_val->value, b_val->value, a_val->type)) {
+        if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
+            assert(a_val->special == ConstValSpecialStatic);
+            assert(b_val->special == ConstValSpecialStatic);
+            if (!const_values_equal(a_val, b_val)) {
                 return false;
             }
         } else {
-            assert(!a_val->value && !b_val->value);
+            assert(a_val->special == ConstValSpecialRuntime && b_val->special == ConstValSpecialRuntime);
         }
     }
     return true;
@@ -2723,7 +2725,7 @@ uint32_t fn_eval_hash(Scope* scope) {
     while (scope) {
         if (scope->id == ScopeIdVarDecl) {
             ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
-            result += hash_const_val(var_scope->var->type, var_scope->var->value);
+            result += hash_const_val(&var_scope->var->value);
         } else if (scope->id == ScopeIdFnDef) {
             ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
             result += hash_ptr(fn_scope->fn_entry);
@@ -2745,9 +2747,9 @@ bool fn_eval_eql(Scope *a, Scope *b) {
         if (a->id == ScopeIdVarDecl) {
             ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
             ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
-            if (a_var_scope->var->type != b_var_scope->var->type)
+            if (a_var_scope->var->value.type != b_var_scope->var->value.type)
                 return false;
-            if (!const_values_equal(a_var_scope->var->value, b_var_scope->var->value, a_var_scope->var->type))
+            if (!const_values_equal(&a_var_scope->var->value, &b_var_scope->var->value))
                 return false;
         } else if (a->id == ScopeIdFnDef) {
             ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
@@ -2865,77 +2867,187 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) {
     return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref);
 }
 
-void init_const_str_lit(ConstExprValue *const_val, Buf *str) {
+void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
     const_val->data.x_array.elements = allocate<ConstExprValue>(buf_len(str));
     const_val->data.x_array.size = buf_len(str);
 
     for (size_t i = 0; i < buf_len(str); i += 1) {
         ConstExprValue *this_char = &const_val->data.x_array.elements[i];
         this_char->special = ConstValSpecialStatic;
+        this_char->type = g->builtin_types.entry_u8;
         bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
     }
 }
 
-ConstExprValue *create_const_str_lit(Buf *str) {
+ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_str_lit(g, const_val, str);
+    return const_val;
+}
+
+void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
+    // first we build the underlying array
+    size_t len_with_null = buf_len(str) + 1;
+    ConstExprValue *array_val = allocate<ConstExprValue>(1);
+    array_val->special = ConstValSpecialStatic;
+    array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null);
+    array_val->data.x_array.elements = allocate<ConstExprValue>(len_with_null);
+    array_val->data.x_array.size = len_with_null;
+    for (size_t i = 0; i < buf_len(str); i += 1) {
+        ConstExprValue *this_char = &array_val->data.x_array.elements[i];
+        this_char->special = ConstValSpecialStatic;
+        this_char->type = g->builtin_types.entry_u8;
+        bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
+    }
+    ConstExprValue *null_char = &array_val->data.x_array.elements[len_with_null - 1];
+    null_char->special = ConstValSpecialStatic;
+    null_char->type = g->builtin_types.entry_u8;
+    bignum_init_unsigned(&null_char->data.x_bignum, 0);
+
+    // then make the pointer point to it
+    const_val->special = ConstValSpecialStatic;
+    const_val->type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
+    const_val->data.x_ptr.base_ptr = array_val;
+    const_val->data.x_ptr.index = 0;
+    const_val->data.x_ptr.special = ConstPtrSpecialCStr;
+}
+ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_str_lit(const_val, str);
+    init_const_c_str_lit(g, const_val, str);
     return const_val;
 }
 
-void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative) {
+void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = type;
     bignum_init_unsigned(&const_val->data.x_bignum, x);
     const_val->data.x_bignum.is_negative = negative;
 }
 
-ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative) {
+ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_unsigned_negative(const_val, x, negative);
+    init_const_unsigned_negative(const_val, type, x, negative);
     return const_val;
 }
 
-void init_const_signed(ConstExprValue *const_val, int64_t x) {
+void init_const_usize(CodeGen *g, ConstExprValue *const_val, uint64_t x) {
+    return init_const_unsigned_negative(const_val, g->builtin_types.entry_usize, x, false);
+}
+
+ConstExprValue *create_const_usize(CodeGen *g, uint64_t x) {
+    return create_const_unsigned_negative(g->builtin_types.entry_usize, x, false);
+}
+
+void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = type;
     bignum_init_signed(&const_val->data.x_bignum, x);
 }
 
-ConstExprValue *create_const_signed(int64_t x) {
+ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_signed(const_val, x);
+    init_const_signed(const_val, type, x);
     return const_val;
 }
 
-void init_const_float(ConstExprValue *const_val, double value) {
+void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = type;
     bignum_init_float(&const_val->data.x_bignum, value);
 }
 
-ConstExprValue *create_const_float(double value) {
+ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_float(const_val, value);
+    init_const_float(const_val, type, value);
     return const_val;
 }
 
-void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag) {
+void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = type;
     const_val->data.x_enum.tag = tag;
 }
 
-ConstExprValue *create_const_enum_tag(uint64_t tag) {
+ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_enum_tag(const_val, tag);
+    init_const_enum_tag(const_val, type, tag);
     return const_val;
 }
 
-void init_const_bool(ConstExprValue *const_val, bool value) {
+void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) {
     const_val->special = ConstValSpecialStatic;
+    const_val->type = g->builtin_types.entry_bool;
     const_val->data.x_bool = value;
 }
 
-ConstExprValue *create_const_bool(bool value) {
+ConstExprValue *create_const_bool(CodeGen *g, bool value) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_bool(g, const_val, value);
+    return const_val;
+}
+
+void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type) {
+    const_val->special = ConstValSpecialRuntime;
+    const_val->type = type;
+}
+
+ConstExprValue *create_const_runtime(TypeTableEntry *type) {
     ConstExprValue *const_val = allocate<ConstExprValue>(1);
-    init_const_bool(const_val, value);
+    init_const_runtime(const_val, type);
+    return const_val;
+}
+
+void init_const_type(CodeGen *g, ConstExprValue *const_val, TypeTableEntry *type_value) {
+    const_val->special = ConstValSpecialStatic;
+    const_val->type = g->builtin_types.entry_type;
+    const_val->data.x_type = type_value;
+}
+
+ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_type(g, const_val, type_value);
+    return const_val;
+}
+
+void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
+        size_t start, size_t len, bool is_const)
+{
+    assert(array_val->type->id == TypeTableEntryIdArray);
+
+    const_val->special = ConstValSpecialStatic;
+    const_val->type = get_slice_type(g, array_val->type->data.array.child_type, is_const);
+    const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
+
+    init_const_ptr(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);
+    init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
+}
+
+ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_slice(g, const_val, array_val, start, len, is_const);
+    return const_val;
+}
+
+void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const) {
+    TypeTableEntry *child_type;
+    if (index == SIZE_MAX) {
+        child_type = base_ptr->type;
+    } else {
+        assert(base_ptr->type->id == TypeTableEntryIdArray);
+        child_type = base_ptr->type->data.array.child_type;
+    }
+
+    const_val->special = ConstValSpecialStatic;
+    const_val->type = get_pointer_to_type(g, child_type, is_const);
+    const_val->data.x_ptr.base_ptr = base_ptr;
+    const_val->data.x_ptr.index = index;
+}
+
+ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t index, bool is_const) {
+    ConstExprValue *const_val = allocate<ConstExprValue>(1);
+    init_const_ptr(g, const_val, base_ptr, index, is_const);
     return const_val;
 }
 
@@ -2956,18 +3068,21 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) {
     if (!var->is_comptime)
         return false;
     if (var->is_comptime->other)
-        return var->is_comptime->other->static_value.data.x_bool;
-    return var->is_comptime->static_value.data.x_bool;
+        return var->is_comptime->other->value.data.x_bool;
+    return var->is_comptime->value.data.x_bool;
 }
 
-bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry) {
-    switch (type_entry->id) {
+bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
+    assert(a->type == b->type);
+    assert(a->special == ConstValSpecialStatic);
+    assert(b->special == ConstValSpecialStatic);
+    switch (a->type->id) {
         case TypeTableEntryIdEnum:
             {
                 ConstEnumValue *enum1 = &a->data.x_enum;
                 ConstEnumValue *enum2 = &b->data.x_enum;
                 if (enum1->tag == enum2->tag) {
-                    TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum1->tag];
+                    TypeEnumField *enum_field = &a->type->data.enumeration.fields[enum1->tag];
                     if (type_has_bits(enum_field->type_entry)) {
                         zig_panic("TODO const expr analyze enum special value for equality");
                     } else {
@@ -2990,9 +3105,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
         case TypeTableEntryIdFloat:
         case TypeTableEntryIdNumLitFloat:
         case TypeTableEntryIdNumLitInt:
-            return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
         case TypeTableEntryIdEnumTag:
-            return const_values_equal(a, b, type_entry->data.enum_tag.int_type);
+            return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
         case TypeTableEntryIdPointer:
             zig_panic("TODO");
         case TypeTableEntryIdArray:
src/analyze.hpp
@@ -66,7 +66,7 @@ FnTableEntry *scope_fn_entry(Scope *scope);
 ImportTableEntry *get_scope_import(Scope *scope);
 void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
 VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
-    TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value);
+    bool is_const, ConstExprValue *init_value);
 TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
 FnTableEntry *create_fn(AstNode *proto_node);
 FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage);
@@ -77,7 +77,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry);
 void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry);
 void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
 bool ir_get_var_is_comptime(VariableTableEntry *var);
-bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *type_entry);
+bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
 void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
 
 ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
@@ -88,22 +88,42 @@ Scope *create_loop_scope(AstNode *node, Scope *parent);
 ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
 ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
 
-void init_const_str_lit(ConstExprValue *const_val, Buf *str);
-ConstExprValue *create_const_str_lit(Buf *str);
+void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
+ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
 
-void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative);
-ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative);
+void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
+ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
 
-void init_const_signed(ConstExprValue *const_val, int64_t x);
-ConstExprValue *create_const_signed(int64_t x);
+void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative);
+ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative);
 
-void init_const_float(ConstExprValue *const_val, double value);
-ConstExprValue *create_const_float(double value);
+void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x);
+ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x);
 
-void init_const_enum_tag(ConstExprValue *const_val, uint64_t tag);
-ConstExprValue *create_const_enum_tag(uint64_t tag);
+void init_const_usize(CodeGen *g, ConstExprValue *const_val, uint64_t x);
+ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
 
-void init_const_bool(ConstExprValue *const_val, bool value);
-ConstExprValue *create_const_bool(bool value);
+void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
+ConstExprValue *create_const_float(TypeTableEntry *type, double value);
+
+void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag);
+ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag);
+
+void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
+ConstExprValue *create_const_bool(CodeGen *g, bool value);
+
+void init_const_type(CodeGen *g, ConstExprValue *const_val, TypeTableEntry *type_value);
+ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value);
+
+void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type);
+ConstExprValue *create_const_runtime(TypeTableEntry *type);
+
+void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const);
+ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr,
+        size_t index, bool is_const);
+
+void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
+        size_t start, size_t len, bool is_const);
+ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);
 
 #endif
src/codegen.cpp
@@ -225,8 +225,8 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
     g->linker_rdynamic = rdynamic;
 }
 
-static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
-static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
+static void render_const_val(CodeGen *g, ConstExprValue *const_val);
+static void render_const_val_global(CodeGen *g, ConstExprValue *const_val);
 
 static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
     if (fn_table_entry->llvm_value)
@@ -645,18 +645,14 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
     return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
 }
 
-static LLVMValueRef gen_assign_raw(CodeGen *g,
-        LLVMValueRef target_ref, LLVMValueRef value,
-        TypeTableEntry *op1_type, TypeTableEntry *op2_type)
+static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef target_ref, LLVMValueRef value,
+        TypeTableEntry *child_type)
 {
-    if (!type_has_bits(op1_type)) {
+    if (!type_has_bits(child_type))
         return nullptr;
-    }
-    if (handle_is_ptr(op1_type)) {
-        assert(op1_type == op2_type);
 
-        return gen_struct_memcpy(g, value, target_ref, op1_type);
-    }
+    if (handle_is_ptr(child_type))
+        return gen_struct_memcpy(g, value, target_ref, child_type);
 
     LLVMBuildStore(g->builder, value, target_ref);
     return nullptr;
@@ -671,17 +667,17 @@ static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) {
 }
 
 static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
-    if (!type_has_bits(instruction->type_entry))
+    if (!type_has_bits(instruction->value.type))
         return nullptr;
     if (!instruction->llvm_value) {
-        assert(instruction->static_value.special != ConstValSpecialRuntime);
-        assert(instruction->type_entry);
-        render_const_val(g, instruction->type_entry, &instruction->static_value);
-        if (handle_is_ptr(instruction->type_entry)) {
-            render_const_val_global(g, instruction->type_entry, &instruction->static_value);
-            instruction->llvm_value = instruction->static_value.llvm_global;
+        assert(instruction->value.special != ConstValSpecialRuntime);
+        assert(instruction->value.type);
+        render_const_val(g, &instruction->value);
+        if (handle_is_ptr(instruction->value.type)) {
+            render_const_val_global(g, &instruction->value);
+            instruction->llvm_value = instruction->value.llvm_global;
         } else {
-            instruction->llvm_value = instruction->static_value.llvm_value;
+            instruction->llvm_value = instruction->value.llvm_value;
         }
         assert(instruction->llvm_value);
     }
@@ -690,7 +686,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
 
 static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
     LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
-    TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
+    TypeTableEntry *return_type = return_instruction->value->value.type;
     bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern;
     if (handle_is_ptr(return_type)) {
         if (is_extern) {
@@ -698,7 +694,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
             LLVMBuildRet(g->builder, by_val_value);
         } else {
             assert(g->cur_ret_ptr);
-            gen_assign_raw(g, g->cur_ret_ptr, value, return_type, return_instruction->value->type_entry);
+            gen_assign_raw(g, g->cur_ret_ptr, value, return_type);
             LLVMBuildRetVoid(g->builder);
         }
     } else {
@@ -809,7 +805,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
     IrInstruction *op1 = bin_op_instruction->op1;
     IrInstruction *op2 = bin_op_instruction->op2;
 
-    assert(op1->type_entry == op2->type_entry);
+    assert(op1->value.type == op2->value.type);
 
     bool want_debug_safety = bin_op_instruction->safety_check_on &&
         ir_want_debug_safety(g, &bin_op_instruction->base);
@@ -831,22 +827,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
         case IrBinOpCmpGreaterThan:
         case IrBinOpCmpLessOrEq:
         case IrBinOpCmpGreaterOrEq:
-            if (op1->type_entry->id == TypeTableEntryIdFloat) {
+            if (op1->value.type->id == TypeTableEntryIdFloat) {
                 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
                 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
-            } else if (op1->type_entry->id == TypeTableEntryIdInt) {
-                LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->type_entry->data.integral.is_signed);
+            } else if (op1->value.type->id == TypeTableEntryIdInt) {
+                LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->value.type->data.integral.is_signed);
                 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
-            } else if (op1->type_entry->id == TypeTableEntryIdEnum) {
-                if (op1->type_entry->data.enumeration.gen_field_count == 0) {
+            } else if (op1->value.type->id == TypeTableEntryIdEnum) {
+                if (op1->value.type->data.enumeration.gen_field_count == 0) {
                     LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
                     return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
                 } else {
                     zig_unreachable();
                 }
-            } else if (op1->type_entry->id == TypeTableEntryIdPureError ||
-                    op1->type_entry->id == TypeTableEntryIdPointer ||
-                    op1->type_entry->id == TypeTableEntryIdBool)
+            } else if (op1->value.type->id == TypeTableEntryIdPureError ||
+                    op1->value.type->id == TypeTableEntryIdPointer ||
+                    op1->value.type->id == TypeTableEntryIdBool)
             {
                 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
                 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
@@ -855,15 +851,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
             }
         case IrBinOpAdd:
         case IrBinOpAddWrap:
-            if (op1->type_entry->id == TypeTableEntryIdFloat) {
+            if (op1->value.type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
-            } else if (op1->type_entry->id == TypeTableEntryIdInt) {
+            } else if (op1->value.type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpAddWrap);
                 if (is_wrapping) {
                     return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value);
-                } else if (op1->type_entry->data.integral.is_signed) {
+                    return gen_overflow_op(g, op1->value.type, AddSubMulAdd, op1_value, op2_value);
+                } else if (op1->value.type->data.integral.is_signed) {
                     return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
@@ -880,36 +876,36 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
         case IrBinOpBitShiftLeft:
         case IrBinOpBitShiftLeftWrap:
             {
-                assert(op1->type_entry->id == TypeTableEntryIdInt);
+                assert(op1->value.type->id == TypeTableEntryIdInt);
                 bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
                 if (is_wrapping) {
                     return LLVMBuildShl(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
-                } else if (op1->type_entry->data.integral.is_signed) {
+                    return gen_overflow_shl_op(g, op1->value.type, op1_value, op2_value);
+                } else if (op1->value.type->data.integral.is_signed) {
                     return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
                 } else {
                     return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
                 }
             }
         case IrBinOpBitShiftRight:
-            assert(op1->type_entry->id == TypeTableEntryIdInt);
-            if (op1->type_entry->data.integral.is_signed) {
+            assert(op1->value.type->id == TypeTableEntryIdInt);
+            if (op1->value.type->data.integral.is_signed) {
                 return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
             } else {
                 return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
             }
         case IrBinOpSub:
         case IrBinOpSubWrap:
-            if (op1->type_entry->id == TypeTableEntryIdFloat) {
+            if (op1->value.type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
-            } else if (op1->type_entry->id == TypeTableEntryIdInt) {
+            } else if (op1->value.type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpSubWrap);
                 if (is_wrapping) {
                     return LLVMBuildSub(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
-                } else if (op1->type_entry->data.integral.is_signed) {
+                    return gen_overflow_op(g, op1->value.type, AddSubMulSub, op1_value, op2_value);
+                } else if (op1->value.type->data.integral.is_signed) {
                     return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
@@ -919,15 +915,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
             }
         case IrBinOpMult:
         case IrBinOpMultWrap:
-            if (op1->type_entry->id == TypeTableEntryIdFloat) {
+            if (op1->value.type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
-            } else if (op1->type_entry->id == TypeTableEntryIdInt) {
+            } else if (op1->value.type->id == TypeTableEntryIdInt) {
                 bool is_wrapping = (op_id == IrBinOpMultWrap);
                 if (is_wrapping) {
                     return LLVMBuildMul(g->builder, op1_value, op2_value, "");
                 } else if (want_debug_safety) {
-                    return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
-                } else if (op1->type_entry->data.integral.is_signed) {
+                    return gen_overflow_op(g, op1->value.type, AddSubMulMul, op1_value, op2_value);
+                } else if (op1->value.type->data.integral.is_signed) {
                     return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
@@ -936,13 +932,13 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
                 zig_unreachable();
             }
         case IrBinOpDiv:
-            return gen_div(g, want_debug_safety, op1_value, op2_value, op1->type_entry, false);
+            return gen_div(g, want_debug_safety, op1_value, op2_value, op1->value.type, false);
         case IrBinOpMod:
-            if (op1->type_entry->id == TypeTableEntryIdFloat) {
+            if (op1->value.type->id == TypeTableEntryIdFloat) {
                 return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
             } else {
-                assert(op1->type_entry->id == TypeTableEntryIdInt);
-                if (op1->type_entry->data.integral.is_signed) {
+                assert(op1->value.type->id == TypeTableEntryIdInt);
+                if (op1->value.type->data.integral.is_signed) {
                     return LLVMBuildSRem(g->builder, op1_value, op2_value, "");
                 } else {
                     return LLVMBuildURem(g->builder, op1_value, op2_value, "");
@@ -955,8 +951,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
 static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
         IrInstructionCast *cast_instruction)
 {
-    TypeTableEntry *actual_type = cast_instruction->value->type_entry;
-    TypeTableEntry *wanted_type = cast_instruction->base.type_entry;
+    TypeTableEntry *actual_type = cast_instruction->value->value.type;
+    TypeTableEntry *wanted_type = cast_instruction->base.value.type;
     LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value);
     assert(expr_val);
 
@@ -977,35 +973,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
             return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
         case CastOpIntToPtr:
             return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
-        case CastOpPointerReinterpret:
-            return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
         case CastOpWidenOrShorten:
             return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
                 actual_type, wanted_type, expr_val);
-        case CastOpToUnknownSizeArray:
-            {
-                assert(cast_instruction->tmp_ptr);
-                assert(wanted_type->id == TypeTableEntryIdStruct);
-                assert(wanted_type->data.structure.is_slice);
-
-                TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
-
-
-                size_t ptr_index = wanted_type->data.structure.fields[0].gen_index;
-                if (ptr_index != SIZE_MAX) {
-                    LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, ptr_index, "");
-                    LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
-                    LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
-                }
-
-                size_t len_index = wanted_type->data.structure.fields[1].gen_index;
-                LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, len_index, "");
-                LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
-                        actual_type->data.array.len, false);
-                LLVMBuildStore(g->builder, len_val, len_ptr);
-
-                return cast_instruction->tmp_ptr;
-            }
         case CastOpResizeSlice:
             {
                 assert(cast_instruction->tmp_ptr);
@@ -1123,6 +1093,15 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
     zig_unreachable();
 }
 
+static LLVMValueRef ir_render_pointer_reinterpret(CodeGen *g, IrExecutable *executable,
+        IrInstructionPointerReinterpret *instruction)
+{
+    TypeTableEntry *wanted_type = instruction->base.value.type;
+    LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+    return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
+}
+
+
 static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable,
         IrInstructionUnreachable *unreachable_instruction)
 {
@@ -1152,7 +1131,7 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc
 static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) {
     IrUnOp op_id = un_op_instruction->op_id;
     LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value);
-    TypeTableEntry *expr_type = un_op_instruction->value->type_entry;
+    TypeTableEntry *expr_type = un_op_instruction->value->value.type;
 
     switch (op_id) {
         case IrUnOpInvalid:
@@ -1213,7 +1192,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
 {
     VariableTableEntry *var = decl_var_instruction->var;
 
-    if (!type_has_bits(var->type))
+    if (!type_has_bits(var->value.type))
         return nullptr;
 
     if (var->ref_count == 0)
@@ -1224,22 +1203,23 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
     bool have_init_expr = false;
     bool want_zeroes = false;
 
-    ConstExprValue *const_val = &init_value->static_value;
+    ConstExprValue *const_val = &init_value->value;
     if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
         have_init_expr = true;
     if (const_val->special == ConstValSpecialZeroes)
         want_zeroes = true;
 
     if (have_init_expr) {
-        gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->type, init_value->type_entry);
+        assert(var->value.type == init_value->value.type);
+        gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->value.type);
     } else {
         bool ignore_uninit = false;
         // handle runtime stack allocation
         bool want_safe = ir_want_debug_safety(g, &decl_var_instruction->base);
         if (!ignore_uninit && (want_safe || want_zeroes)) {
             TypeTableEntry *usize = g->builtin_types.entry_usize;
-            uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->type->type_ref);
-            uint64_t align_bytes = get_memcpy_align(g, var->type);
+            uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value.type->type_ref);
+            uint64_t align_bytes = get_memcpy_align(g, var->value.type);
 
             // memset uninitialized memory to 0xa
             LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
@@ -1265,16 +1245,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
 
 static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
     LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
-    return get_handle_value(g, ptr, instruction->base.type_entry);
+    return get_handle_value(g, ptr, instruction->base.value.type);
 }
 
 static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
     LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
     LLVMValueRef value = ir_llvm_value(g, instruction->value);
 
-    assert(instruction->ptr->type_entry->id == TypeTableEntryIdPointer);
-    TypeTableEntry *op1_type = instruction->ptr->type_entry->data.pointer.child_type;
-    TypeTableEntry *op2_type = instruction->value->type_entry;
+    assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer);
+    TypeTableEntry *op1_type = instruction->ptr->value.type->data.pointer.child_type;
+    TypeTableEntry *op2_type = instruction->value->value.type;
 
     if (!type_has_bits(op1_type)) {
         return nullptr;
@@ -1290,7 +1270,7 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
 
 static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
     VariableTableEntry *var = instruction->var;
-    if (type_has_bits(var->type)) {
+    if (type_has_bits(var->value.type)) {
         assert(var->value_ref);
         return var->value_ref;
     } else {
@@ -1300,7 +1280,7 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
 
 static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
     LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
-    TypeTableEntry *array_ptr_type = instruction->array_ptr->type_entry;
+    TypeTableEntry *array_ptr_type = instruction->array_ptr->value.type;
     assert(array_ptr_type->id == TypeTableEntryIdPointer);
     TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
     LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type);
@@ -1361,7 +1341,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
     } else {
         assert(instruction->fn_ref);
         fn_val = ir_llvm_value(g, instruction->fn_ref);
-        fn_type = instruction->fn_ref->type_entry;
+        fn_type = instruction->fn_ref->value.type;
     }
 
     TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
@@ -1377,7 +1357,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
     }
     for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
         IrInstruction *param_instruction = instruction->args[call_i];
-        TypeTableEntry *param_type = param_instruction->type_entry;
+        TypeTableEntry *param_type = param_instruction->value.type;
         if (is_var_args || type_has_bits(param_type)) {
             LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
             assert(param_value);
@@ -1526,7 +1506,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
             buf_append_char(&constraint_buf, ',');
         }
 
-        param_types[param_index] = ir_input->type_entry->type_ref;
+        param_types[param_index] = ir_input->value.type->type_ref;
         param_values[param_index] = ir_llvm_value(g, ir_input);
     }
     for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
@@ -1541,7 +1521,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
     if (instruction->return_count == 0) {
         ret_type = LLVMVoidType();
     } else {
-        ret_type = instruction->base.type_entry->type_ref;
+        ret_type = instruction->base.value.type->type_ref;
     }
     LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false);
 
@@ -1565,13 +1545,13 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLV
 static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable,
     IrInstructionTestNonNull *instruction)
 {
-    return gen_non_null_bit(g, instruction->value->type_entry, ir_llvm_value(g, instruction->value));
+    return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
 }
 
 static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
         IrInstructionUnwrapMaybe *instruction)
 {
-    TypeTableEntry *ptr_type = instruction->value->type_entry;
+    TypeTableEntry *ptr_type = instruction->value->value.type;
     assert(ptr_type->id == TypeTableEntryIdPointer);
     TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
     assert(maybe_type->id == TypeTableEntryIdMaybe);
@@ -1617,7 +1597,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui
 }
 
 static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) {
-    TypeTableEntry *int_type = instruction->base.type_entry;
+    TypeTableEntry *int_type = instruction->base.value.type;
     LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz);
     LLVMValueRef operand = ir_llvm_value(g, instruction->value);
     LLVMValueRef params[] {
@@ -1628,7 +1608,7 @@ static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstru
 }
 
 static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) {
-    TypeTableEntry *int_type = instruction->base.type_entry;
+    TypeTableEntry *int_type = instruction->base.value.type;
     LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz);
     LLVMValueRef operand = ir_llvm_value(g, instruction->value);
     LLVMValueRef params[] {
@@ -1650,14 +1630,14 @@ static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, Ir
 }
 
 static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstructionPhi *instruction) {
-    if (!type_has_bits(instruction->base.type_entry))
+    if (!type_has_bits(instruction->base.value.type))
         return nullptr;
 
     LLVMTypeRef phi_type;
-    if (handle_is_ptr(instruction->base.type_entry)) {
-        phi_type = LLVMPointerType(instruction->base.type_entry->type_ref, 0);
+    if (handle_is_ptr(instruction->base.value.type)) {
+        phi_type = LLVMPointerType(instruction->base.value.type->type_ref, 0);
     } else {
-        phi_type = instruction->base.type_entry->type_ref;
+        phi_type = instruction->base.value.type->type_ref;
     }
 
     LLVMValueRef phi = LLVMBuildPhi(g->builder, phi_type, "");
@@ -1673,7 +1653,7 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru
 
 static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) {
     LLVMValueRef value = ir_llvm_value(g, instruction->value);
-    if (handle_is_ptr(instruction->value->type_entry)) {
+    if (handle_is_ptr(instruction->value->value.type)) {
         return value;
     } else {
         assert(instruction->tmp_ptr);
@@ -1741,17 +1721,17 @@ static LLVMValueRef ir_render_div_exact(CodeGen *g, IrExecutable *executable, Ir
     LLVMValueRef op2_val = ir_llvm_value(g, instruction->op2);
 
     bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
-    return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.type_entry, true);
+    return gen_div(g, want_debug_safety, op1_val, op2_val, instruction->base.value.type, true);
 }
 
 static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrInstructionTruncate *instruction) {
-    TypeTableEntry *dest_type = get_underlying_type(instruction->base.type_entry);
+    TypeTableEntry *dest_type = get_underlying_type(instruction->base.value.type);
     LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
     return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
 }
 
 static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
-    TypeTableEntry *slice_type = get_underlying_type(instruction->base.type_entry);
+    TypeTableEntry *slice_type = get_underlying_type(instruction->base.value.type);
     TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
     TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
     LLVMValueRef size_val = ir_llvm_value(g, instruction->count);
@@ -1814,12 +1794,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
 }
 
 static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
-    TypeTableEntry *array_type = get_underlying_type(instruction->ptr->type_entry);
+    assert(instruction->tmp_ptr);
+
+    TypeTableEntry *array_type = get_underlying_type(instruction->ptr->value.type);
 
     LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
     LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
 
-    bool want_debug_safety = ir_want_debug_safety(g, &instruction->base);
+    bool want_debug_safety = instruction->safety_check_on && ir_want_debug_safety(g, &instruction->base);
 
     if (array_type->id == TypeTableEntryIdArray) {
         LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
@@ -1997,7 +1979,7 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
 }
 
 static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
-    TypeTableEntry *err_union_type = get_underlying_type(instruction->value->type_entry);
+    TypeTableEntry *err_union_type = get_underlying_type(instruction->value->value.type);
     TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
     LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
 
@@ -2014,7 +1996,7 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
 }
 
 static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
-    TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
+    TypeTableEntry *ptr_type = get_underlying_type(instruction->value->value.type);
     TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
     TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
     LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
@@ -2029,7 +2011,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
 }
 
 static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
-    TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
+    TypeTableEntry *ptr_type = get_underlying_type(instruction->value->value.type);
     TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
     TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
     LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
@@ -2063,7 +2045,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
 }
 
 static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
-    TypeTableEntry *wanted_type = instruction->base.type_entry;
+    TypeTableEntry *wanted_type = instruction->base.value.type;
 
     assert(wanted_type->id == TypeTableEntryIdMaybe);
 
@@ -2079,7 +2061,8 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
     assert(instruction->tmp_ptr);
 
     LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
-    gen_assign_raw(g, val_ptr, payload_val, child_type, instruction->value->type_entry);
+    assert(child_type == instruction->value->value.type);
+    gen_assign_raw(g, val_ptr, payload_val, child_type);
     LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
     LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
 
@@ -2087,7 +2070,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
 }
 
 static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) {
-    TypeTableEntry *wanted_type = instruction->base.type_entry;
+    TypeTableEntry *wanted_type = instruction->base.value.type;
 
     assert(wanted_type->id == TypeTableEntryIdErrorUnion);
 
@@ -2106,7 +2089,7 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
 }
 
 static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) {
-    TypeTableEntry *wanted_type = instruction->base.type_entry;
+    TypeTableEntry *wanted_type = instruction->base.value.type;
 
     assert(wanted_type->id == TypeTableEntryIdErrorUnion);
 
@@ -2125,13 +2108,14 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
     LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
 
     LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
-    gen_assign_raw(g, payload_ptr, payload_val, child_type, instruction->value->type_entry);
+    assert(child_type == instruction->value->value.type);
+    gen_assign_raw(g, payload_ptr, payload_val, child_type);
 
     return instruction->tmp_ptr;
 }
 
 static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
-    TypeTableEntry *enum_type = instruction->value->type_entry;
+    TypeTableEntry *enum_type = instruction->value->value.type;
     TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
     if (!type_has_bits(tag_type))
         return nullptr;
@@ -2165,7 +2149,7 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
         LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
                 LLVMPointerType(union_val_type->type_ref, 0), "");
 
-        gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type, union_val_type);
+        gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type);
     }
 
     return tmp_struct_ptr;
@@ -2180,7 +2164,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
 
         LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, "");
         LLVMValueRef value = ir_llvm_value(g, field->value);
-        gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry, type_struct_field->type_entry);
+        gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry);
     }
     return instruction->tmp_ptr;
 }
@@ -2323,6 +2307,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
         case IrInstructionIdStructInit:
             return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
+        case IrInstructionIdPointerReinterpret:
+            return ir_render_pointer_reinterpret(g, executable, (IrInstructionPointerReinterpret *)instruction);
         case IrInstructionIdSwitchVar:
             zig_panic("TODO render switch var instruction to LLVM");
         case IrInstructionIdContainerInitList:
@@ -2350,37 +2336,40 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
     }
 }
 
-static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
+static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
+    TypeTableEntry *canon_type = get_underlying_type(const_val->type);
+
     switch (const_val->special) {
         case ConstValSpecialRuntime:
             zig_unreachable();
         case ConstValSpecialUndef:
-            return LLVMGetUndef(type_entry->type_ref);
+            return LLVMGetUndef(canon_type->type_ref);
         case ConstValSpecialZeroes:
-            return LLVMConstNull(type_entry->type_ref);
+            return LLVMConstNull(canon_type->type_ref);
         case ConstValSpecialStatic:
             break;
 
     }
 
-    switch (type_entry->id) {
+    switch (canon_type->id) {
         case TypeTableEntryIdTypeDecl:
-            return gen_const_val(g, type_entry->data.type_decl.canonical_type, const_val);
+            zig_unreachable();
         case TypeTableEntryIdInt:
-            return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
+        case TypeTableEntryIdEnumTag:
+            return LLVMConstInt(canon_type->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
         case TypeTableEntryIdPureError:
             assert(const_val->data.x_pure_err);
             return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
                     const_val->data.x_pure_err->value, false);
         case TypeTableEntryIdFloat:
             if (const_val->data.x_bignum.kind == BigNumKindFloat) {
-                return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
+                return LLVMConstReal(canon_type->type_ref, const_val->data.x_bignum.data.x_float);
             } else {
                 int64_t x = const_val->data.x_bignum.data.x_uint;
                 if (const_val->data.x_bignum.is_negative) {
                     x = -x;
                 }
-                return LLVMConstReal(type_entry->type_ref, x);
+                return LLVMConstReal(canon_type->type_ref, x);
             }
         case TypeTableEntryIdBool:
             if (const_val->data.x_bool) {
@@ -2390,12 +2379,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
             }
         case TypeTableEntryIdMaybe:
             {
-                TypeTableEntry *child_type = type_entry->data.maybe.child_type;
+                TypeTableEntry *child_type = canon_type->data.maybe.child_type;
                 if (child_type->id == TypeTableEntryIdPointer ||
                     child_type->id == TypeTableEntryIdFn)
                 {
                     if (const_val->data.x_maybe) {
-                        return gen_const_val(g, child_type, const_val->data.x_maybe);
+                        return gen_const_val(g, const_val->data.x_maybe);
                     } else {
                         return LLVMConstNull(child_type->type_ref);
                     }
@@ -2403,7 +2392,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
                     LLVMValueRef child_val;
                     LLVMValueRef maybe_val;
                     if (const_val->data.x_maybe) {
-                        child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
+                        child_val = gen_const_val(g, const_val->data.x_maybe);
                         maybe_val = LLVMConstAllOnes(LLVMInt1Type());
                     } else {
                         child_val = LLVMConstNull(child_type->type_ref);
@@ -2418,17 +2407,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
             }
         case TypeTableEntryIdStruct:
             {
-                LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
-                for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
-                    TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
+                LLVMValueRef *fields = allocate<LLVMValueRef>(canon_type->data.structure.gen_field_count);
+                for (uint32_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) {
+                    TypeStructField *type_struct_field = &canon_type->data.structure.fields[i];
                     if (type_struct_field->gen_index == SIZE_MAX) {
                         continue;
                     }
-                    fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
-                            &const_val->data.x_struct.fields[i]);
+                    fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]);
                 }
-                return LLVMConstNamedStruct(type_entry->type_ref, fields,
-                        type_entry->data.structure.gen_field_count);
+                return LLVMConstNamedStruct(canon_type->type_ref, fields,
+                        canon_type->data.structure.gen_field_count);
             }
         case TypeTableEntryIdUnion:
             {
@@ -2436,24 +2424,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
             }
         case TypeTableEntryIdArray:
             {
-                TypeTableEntry *child_type = type_entry->data.array.child_type;
-                uint64_t len = type_entry->data.array.len;
+                TypeTableEntry *child_type = canon_type->data.array.child_type;
+                uint64_t len = canon_type->data.array.len;
                 LLVMValueRef *values = allocate<LLVMValueRef>(len);
                 for (uint64_t i = 0; i < len; i += 1) {
                     ConstExprValue *elem_value = &const_val->data.x_array.elements[i];
-                    values[i] = gen_const_val(g, child_type, elem_value);
+                    values[i] = gen_const_val(g, elem_value);
                 }
                 return LLVMConstArray(child_type->type_ref, values, len);
             }
         case TypeTableEntryIdEnum:
             {
-                LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
+                LLVMTypeRef tag_type_ref = canon_type->data.enumeration.tag_type->type_ref;
                 LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
-                if (type_entry->data.enumeration.gen_field_count == 0) {
+                if (canon_type->data.enumeration.gen_field_count == 0) {
                     return tag_value;
                 } else {
-                    TypeTableEntry *union_type = type_entry->data.enumeration.union_type;
-                    TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
+                    TypeTableEntry *union_type = canon_type->data.enumeration.union_type;
+                    TypeEnumField *enum_field = &canon_type->data.enumeration.fields[const_val->data.x_enum.tag];
                     assert(enum_field->value == const_val->data.x_enum.tag);
                     LLVMValueRef union_value;
                     if (type_has_bits(enum_field->type_entry)) {
@@ -2463,8 +2451,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
                                 enum_field->type_entry->type_ref);
                         uint64_t pad_bytes = union_type_bytes - field_type_bytes;
 
-                        LLVMValueRef correctly_typed_value = gen_const_val(g, enum_field->type_entry,
-                                const_val->data.x_enum.payload);
+                        LLVMValueRef correctly_typed_value = gen_const_val(g, const_val->data.x_enum.payload);
                         if (pad_bytes == 0) {
                             union_value = correctly_typed_value;
                         } else {
@@ -2481,29 +2468,31 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
                         tag_value,
                         union_value,
                     };
-                    return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                    return LLVMConstNamedStruct(canon_type->type_ref, fields, 2);
                 }
             }
         case TypeTableEntryIdFn:
             return fn_llvm_value(g, const_val->data.x_fn);
         case TypeTableEntryIdPointer:
             {
-                TypeTableEntry *child_type = type_entry->data.pointer.child_type;
-
-                render_const_val_global(g, type_entry, const_val);
+                render_const_val_global(g, const_val);
                 size_t index = const_val->data.x_ptr.index;
                 if (index == SIZE_MAX) {
-                    render_const_val(g, child_type, const_val->data.x_ptr.base_ptr);
-                    render_const_val_global(g, child_type, const_val->data.x_ptr.base_ptr);
-                    const_val->llvm_value = const_val->data.x_ptr.base_ptr->llvm_global;
-                    render_const_val_global(g, type_entry, const_val);
+                    render_const_val(g, const_val->data.x_ptr.base_ptr);
+                    render_const_val_global(g, const_val->data.x_ptr.base_ptr);
+                    ConstExprValue *other_val = const_val->data.x_ptr.base_ptr;
+                    if (other_val->type == const_val->type->data.pointer.child_type) {
+                        const_val->llvm_value = other_val->llvm_global;
+                    } else {
+                        const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref);
+                    }
+                    render_const_val_global(g, const_val);
                     return const_val->llvm_value;
                 } else {
                     ConstExprValue *array_const_val = const_val->data.x_ptr.base_ptr;
-                    TypeTableEntry *array_type = get_array_type(g, child_type,
-                            array_const_val->data.x_array.size);
-                    render_const_val(g, array_type, array_const_val);
-                    render_const_val_global(g, array_type, array_const_val);
+                    assert(array_const_val->type->id == TypeTableEntryIdArray);
+                    render_const_val(g, array_const_val);
+                    render_const_val_global(g, array_const_val);
                     TypeTableEntry *usize = g->builtin_types.entry_usize;
                     LLVMValueRef indices[] = {
                         LLVMConstNull(usize->type_ref),
@@ -2511,13 +2500,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
                     };
                     LLVMValueRef ptr_val = LLVMConstInBoundsGEP(array_const_val->llvm_global, indices, 2);
                     const_val->llvm_value = ptr_val;
-                    render_const_val_global(g, type_entry, const_val);
+                    render_const_val_global(g, const_val);
                     return ptr_val;
                 }
             }
         case TypeTableEntryIdErrorUnion:
             {
-                TypeTableEntry *child_type = type_entry->data.error.child_type;
+                TypeTableEntry *child_type = canon_type->data.error.child_type;
                 if (!type_has_bits(child_type)) {
                     uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
                     return LLVMConstInt(g->err_tag_type->type_ref, value, false);
@@ -2529,7 +2518,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
                         err_payload_value = LLVMConstNull(child_type->type_ref);
                     } else {
                         err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
-                        err_payload_value = gen_const_val(g, child_type, const_val->data.x_err_union.payload);
+                        err_payload_value = gen_const_val(g, const_val->data.x_err_union.payload);
                     }
                     LLVMValueRef fields[] = {
                         err_tag_value,
@@ -2540,8 +2529,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
             }
         case TypeTableEntryIdVoid:
             return nullptr;
-        case TypeTableEntryIdEnumTag:
-            return gen_const_val(g, type_entry->data.enum_tag.int_type, const_val);
         case TypeTableEntryIdInvalid:
         case TypeTableEntryIdMetaType:
         case TypeTableEntryIdUnreachable:
@@ -2559,17 +2546,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
     zig_unreachable();
 }
 
-static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
+static void render_const_val(CodeGen *g, ConstExprValue *const_val) {
     if (!const_val->llvm_value)
-        const_val->llvm_value = gen_const_val(g, type_entry, const_val);
+        const_val->llvm_value = gen_const_val(g, const_val);
 
     if (const_val->llvm_global)
         LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value);
 }
 
-static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
+static void render_const_val_global(CodeGen *g, ConstExprValue *const_val) {
     if (!const_val->llvm_global) {
-        LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
+        LLVMValueRef global_value = LLVMAddGlobal(g->module, const_val->type->type_ref, "");
         LLVMSetLinkage(global_value, LLVMInternalLinkage);
         LLVMSetGlobalConstant(global_value, true);
         LLVMSetUnnamedAddr(global_value, true);
@@ -2717,9 +2704,9 @@ static void do_code_gen(CodeGen *g) {
     for (size_t i = 0; i < g->global_vars.length; i += 1) {
         VariableTableEntry *var = g->global_vars.at(i);
 
-        if (var->type->id == TypeTableEntryIdNumLitFloat) {
+        if (var->value.type->id == TypeTableEntryIdNumLitFloat) {
             // Generate debug info for it but that's it.
-            ConstExprValue *const_val = var->value;
+            ConstExprValue *const_val = &var->value;
             assert(const_val->special != ConstValSpecialRuntime);
             TypeTableEntry *var_type = g->builtin_types.entry_f64;
             LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
@@ -2727,9 +2714,9 @@ static void do_code_gen(CodeGen *g) {
             continue;
         }
 
-        if (var->type->id == TypeTableEntryIdNumLitInt) {
+        if (var->value.type->id == TypeTableEntryIdNumLitInt) {
             // Generate debug info for it but that's it.
-            ConstExprValue *const_val = var->value;
+            ConstExprValue *const_val = &var->value;
             assert(const_val->special != ConstValSpecialRuntime);
             TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
                 g->builtin_types.entry_isize : g->builtin_types.entry_usize;
@@ -2739,27 +2726,26 @@ static void do_code_gen(CodeGen *g) {
             continue;
         }
 
-        if (!type_has_bits(var->type)) {
+        if (!type_has_bits(var->value.type))
             continue;
-        }
 
         assert(var->decl_node);
         assert(var->decl_node->type == NodeTypeVariableDeclaration);
 
         LLVMValueRef global_value;
         if (var->is_extern) {
-            global_value = LLVMAddGlobal(g->module, var->type->type_ref, buf_ptr(&var->name));
+            global_value = LLVMAddGlobal(g->module, var->value.type->type_ref, buf_ptr(&var->name));
 
             // TODO debug info for the extern variable
 
             LLVMSetLinkage(global_value, LLVMExternalLinkage);
         } else {
-            render_const_val(g, var->type, var->value);
-            render_const_val_global(g, var->type, var->value);
-            global_value = var->value->llvm_global;
+            render_const_val(g, &var->value);
+            render_const_val_global(g, &var->value);
+            global_value = var->value.llvm_global;
             // TODO debug info for function pointers
-            if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) {
-                gen_global_var(g, var, var->value->llvm_value, var->type);
+            if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) {
+                gen_global_var(g, var, var->value.llvm_value, var->value.type);
             }
         }
 
@@ -2890,15 +2876,15 @@ static void do_code_gen(CodeGen *g) {
         for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
             IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
             LLVMValueRef *slot;
-            TypeTableEntry *slot_type = instruction->type_entry;
+            TypeTableEntry *slot_type = instruction->value.type;
             if (instruction->id == IrInstructionIdCast) {
                 IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction;
                 slot = &cast_instruction->tmp_ptr;
             } else if (instruction->id == IrInstructionIdRef) {
                 IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
                 slot = &ref_instruction->tmp_ptr;
-                assert(instruction->type_entry->id == TypeTableEntryIdPointer);
-                slot_type = instruction->type_entry->data.pointer.child_type;
+                assert(instruction->value.type->id == TypeTableEntryIdPointer);
+                slot_type = instruction->value.type->data.pointer.child_type;
             } else if (instruction->id == IrInstructionIdContainerInitList) {
                 IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
                 slot = &container_init_list_instruction->tmp_ptr;
@@ -2938,33 +2924,33 @@ static void do_code_gen(CodeGen *g) {
         for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
             VariableTableEntry *var = fn_table_entry->variable_list.at(var_i);
 
-            if (!type_has_bits(var->type)) {
+            if (!type_has_bits(var->value.type)) {
                 continue;
             }
             if (ir_get_var_is_comptime(var))
                 continue;
 
             if (var->src_arg_index == SIZE_MAX) {
-                var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
+                var->value_ref = LLVMBuildAlloca(g->builder, var->value.type->type_ref, buf_ptr(&var->name));
 
 
-                unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
+                unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->value.type->type_ref);
                 LLVMSetAlignment(var->value_ref, align_bytes);
 
                 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
                         buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
-                        var->type->di_type, !g->strip_debug_symbols, 0);
+                        var->value.type->di_type, !g->strip_debug_symbols, 0);
 
             } else {
                 assert(var->gen_arg_index != SIZE_MAX);
                 TypeTableEntry *gen_type;
-                if (handle_is_ptr(var->type)) {
+                if (handle_is_ptr(var->value.type)) {
                     gen_type = fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index].type;
                     var->value_ref = LLVMGetParam(fn, var->gen_arg_index);
                 } else {
-                    gen_type = var->type;
-                    var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
-                    unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
+                    gen_type = var->value.type;
+                    var->value_ref = LLVMBuildAlloca(g->builder, var->value.type->type_ref, buf_ptr(&var->name));
+                    unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->value.type->type_ref);
                     LLVMSetAlignment(var->value_ref, align_bytes);
                 }
                 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@@ -2991,7 +2977,7 @@ static void do_code_gen(CodeGen *g) {
             assert(variable);
             assert(variable->value_ref);
 
-            if (!handle_is_ptr(variable->type)) {
+            if (!handle_is_ptr(variable->value.type)) {
                 clear_debug_source_node(g);
                 LLVMBuildStore(g->builder, LLVMGetParam(fn, variable->gen_arg_index), variable->value_ref);
             }
@@ -3627,7 +3613,7 @@ static void init(CodeGen *g, Buf *source_path) {
     define_builtin_fns(g);
 
     g->invalid_instruction = allocate<IrInstruction>(1);
-    g->invalid_instruction->type_entry = g->builtin_types.entry_invalid;
+    g->invalid_instruction->value.type = g->builtin_types.entry_invalid;
 }
 
 void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {
src/ir.cpp
@@ -48,6 +48,7 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
 static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope,
         LValPurpose lval);
 static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
+static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
 
 ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {
     assert(const_val->special == ConstValSpecialStatic);
@@ -93,7 +94,7 @@ static Buf *exec_c_import_buf(IrExecutable *exec) {
 }
 
 static bool instr_is_comptime(IrInstruction *instruction) {
-    return instruction->static_value.special != ConstValSpecialRuntime;
+    return instruction->value.special != ConstValSpecialRuntime;
 }
 
 static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) {
@@ -450,6 +451,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) {
     return IrInstructionIdInitEnum;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPointerReinterpret *) {
+    return IrInstructionIdPointerReinterpret;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -485,8 +490,8 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
         IrBasicBlock *then_block, IrBasicBlock *else_block, IrInstruction *is_comptime)
 {
     IrInstructionCondBr *cond_br_instruction = ir_build_instruction<IrInstructionCondBr>(irb, scope, source_node);
-    cond_br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
-    cond_br_instruction->base.static_value.special = ConstValSpecialStatic;
+    cond_br_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
+    cond_br_instruction->base.value.special = ConstValSpecialStatic;
     cond_br_instruction->condition = condition;
     cond_br_instruction->then_block = then_block;
     cond_br_instruction->else_block = else_block;
@@ -511,8 +516,8 @@ static IrInstruction *ir_build_cond_br_from(IrBuilder *irb, IrInstruction *old_i
 
 static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) {
     IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);
-    return_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
-    return_instruction->base.static_value.special = ConstValSpecialStatic;
+    return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
+    return_instruction->base.value.special = ConstValSpecialStatic;
     return_instruction->value = return_value;
 
     ir_ref_instruction(return_value);
@@ -533,55 +538,55 @@ static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *sou
 {
     assert(type_entry);
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, scope, source_node);
-    const_instruction->base.type_entry = type_entry;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var;
+    const_instruction->base.value.type = type_entry;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.depends_on_compile_var = depends_on_compile_var;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
+    const_instruction->base.value.special = ConstValSpecialStatic;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_undefined(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.static_value.special = ConstValSpecialUndef;
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_undef;
+    const_instruction->base.value.special = ConstValSpecialUndef;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_undef;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_uint(IrBuilder *irb, Scope *scope, AstNode *source_node, uint64_t value) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_num_lit_int;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, value);
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_num_lit_int;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, value);
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_bignum(IrBuilder *irb, Scope *scope, AstNode *source_node, BigNum *bignum) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = (bignum->kind == BigNumKindInt) ?
+    const_instruction->base.value.type = (bignum->kind == BigNumKindInt) ?
         irb->codegen->builtin_types.entry_num_lit_int : irb->codegen->builtin_types.entry_num_lit_float;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_bignum = *bignum;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_bignum = *bignum;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_null(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_null;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_null;
+    const_instruction->base.value.special = ConstValSpecialStatic;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode *source_node, uint64_t value) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_usize;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, value);
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_usize;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, value);
     return &const_instruction->base;
 }
 
@@ -589,9 +594,9 @@ static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode
         TypeTableEntry *type_entry)
 {
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_type = type_entry;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_type;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_type = type_entry;
     return &const_instruction->base;
 }
 
@@ -605,17 +610,17 @@ static IrInstruction *ir_build_const_type(IrBuilder *irb, Scope *scope, AstNode
 
 static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = fn_entry->type_entry;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_fn = fn_entry;
+    const_instruction->base.value.type = fn_entry->type_entry;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_fn = fn_entry;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_namespace;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_import = import;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_import = import;
     return &const_instruction->base;
 }
 
@@ -623,17 +628,17 @@ static IrInstruction *ir_build_const_scope(IrBuilder *irb, Scope *parent_scope,
         Scope *target_scope)
 {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, parent_scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_block;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_block = target_scope;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_block;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_block = target_scope;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_build_const_bool(IrBuilder *irb, Scope *scope, AstNode *source_node, bool value) {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = irb->codegen->builtin_types.entry_bool;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.data.x_bool = value;
+    const_instruction->base.value.type = irb->codegen->builtin_types.entry_bool;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.data.x_bool = value;
     return &const_instruction->base;
 }
 
@@ -641,21 +646,17 @@ static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, Scope *scope, AstN
     FnTableEntry *fn_entry, IrInstruction *first_arg, bool depends_on_compile_var)
 {
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    const_instruction->base.type_entry = get_bound_fn_type(irb->codegen, fn_entry);
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var;
-    const_instruction->base.static_value.data.x_bound_fn.fn = fn_entry;
-    const_instruction->base.static_value.data.x_bound_fn.first_arg = first_arg;
+    const_instruction->base.value.type = get_bound_fn_type(irb->codegen, fn_entry);
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.depends_on_compile_var = depends_on_compile_var;
+    const_instruction->base.value.data.x_bound_fn.fn = fn_entry;
+    const_instruction->base.value.data.x_bound_fn.first_arg = first_arg;
     return &const_instruction->base;
 }
 
 static IrInstruction *ir_create_const_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) {
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, scope, source_node);
-    TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8;
-    TypeTableEntry *type_entry = get_array_type(irb->codegen, u8_type, buf_len(str));
-    const_instruction->base.type_entry = type_entry;
-    ConstExprValue *const_val = &const_instruction->base.static_value;
-    init_const_str_lit(const_val, str);
+    init_const_str_lit(irb->codegen, &const_instruction->base.value, str);
 
     return &const_instruction->base;
 }
@@ -666,32 +667,8 @@ static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, Scope *scope, AstNo
 }
 
 static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) {
-    // first we build the underlying array
-    size_t len_with_null = buf_len(str) + 1;
-    ConstExprValue *array_val = allocate<ConstExprValue>(1);
-    array_val->special = ConstValSpecialStatic;
-    array_val->data.x_array.elements = allocate<ConstExprValue>(len_with_null);
-    array_val->data.x_array.size = len_with_null;
-    for (size_t i = 0; i < buf_len(str); i += 1) {
-        ConstExprValue *this_char = &array_val->data.x_array.elements[i];
-        this_char->special = ConstValSpecialStatic;
-        bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
-    }
-    ConstExprValue *null_char = &array_val->data.x_array.elements[len_with_null - 1];
-    null_char->special = ConstValSpecialStatic;
-    bignum_init_unsigned(&null_char->data.x_bignum, 0);
-
-    // then make the pointer point to it
     IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
-    TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8;
-    TypeTableEntry *type_entry = get_pointer_to_type(irb->codegen, u8_type, true);
-    const_instruction->base.type_entry = type_entry;
-    ConstExprValue *ptr_val = &const_instruction->base.static_value;
-    ptr_val->special = ConstValSpecialStatic;
-    ptr_val->data.x_ptr.base_ptr = array_val;
-    ptr_val->data.x_ptr.index = 0;
-    ptr_val->data.x_ptr.special = ConstPtrSpecialCStr;
-
+    init_const_c_str_lit(irb->codegen, &const_instruction->base.value, str);
     return &const_instruction->base;
 }
 
@@ -870,8 +847,8 @@ static IrInstruction *ir_create_br(IrBuilder *irb, Scope *scope, AstNode *source
         IrBasicBlock *dest_block, IrInstruction *is_comptime)
 {
     IrInstructionBr *br_instruction = ir_create_instruction<IrInstructionBr>(irb->exec, scope, source_node);
-    br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
-    br_instruction->base.static_value.special = ConstValSpecialStatic;
+    br_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
+    br_instruction->base.value.special = ConstValSpecialStatic;
     br_instruction->dest_block = dest_block;
     br_instruction->is_comptime = is_comptime;
 
@@ -983,8 +960,8 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o
 static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     IrInstructionUnreachable *unreachable_instruction =
         ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node);
-    unreachable_instruction->base.static_value.special = ConstValSpecialStatic;
-    unreachable_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
+    unreachable_instruction->base.value.special = ConstValSpecialStatic;
+    unreachable_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
     return &unreachable_instruction->base;
 }
 
@@ -998,8 +975,8 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
         IrInstruction *ptr, IrInstruction *value)
 {
     IrInstructionStorePtr *instruction = ir_build_instruction<IrInstructionStorePtr>(irb, scope, source_node);
-    instruction->base.static_value.special = ConstValSpecialStatic;
-    instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
+    instruction->base.value.special = ConstValSpecialStatic;
+    instruction->base.value.type = irb->codegen->builtin_types.entry_void;
     instruction->ptr = ptr;
     instruction->value = value;
 
@@ -1022,8 +999,8 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s
         VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value)
 {
     IrInstructionDeclVar *decl_var_instruction = ir_build_instruction<IrInstructionDeclVar>(irb, scope, source_node);
-    decl_var_instruction->base.static_value.special = ConstValSpecialStatic;
-    decl_var_instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
+    decl_var_instruction->base.value.special = ConstValSpecialStatic;
+    decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
     decl_var_instruction->var = var;
     decl_var_instruction->var_type = var_type;
     decl_var_instruction->init_value = init_value;
@@ -1302,8 +1279,8 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
         IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime)
 {
     IrInstructionSwitchBr *instruction = ir_build_instruction<IrInstructionSwitchBr>(irb, scope, source_node);
-    instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
-    instruction->base.static_value.special = ConstValSpecialStatic;
+    instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
+    instruction->base.value.special = ConstValSpecialStatic;
     instruction->target_value = target_value;
     instruction->else_block = else_block;
     instruction->case_count = case_count;
@@ -1682,13 +1659,14 @@ static IrInstruction *ir_build_memcpy_from(IrBuilder *irb, IrInstruction *old_in
 }
 
 static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
-    IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const)
+    IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const, bool safety_check_on)
 {
     IrInstructionSlice *instruction = ir_build_instruction<IrInstructionSlice>(irb, scope, source_node);
     instruction->ptr = ptr;
     instruction->start = start;
     instruction->end = end;
     instruction->is_const = is_const;
+    instruction->safety_check_on = safety_check_on;
 
     ir_ref_instruction(ptr);
     ir_ref_instruction(start);
@@ -1698,9 +1676,10 @@ static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *sour
 }
 
 static IrInstruction *ir_build_slice_from(IrBuilder *irb, IrInstruction *old_instruction,
-    IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const)
+    IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool is_const, bool safety_check_on)
 {
-    IrInstruction *new_instruction = ir_build_slice(irb, old_instruction->scope, old_instruction->source_node, ptr, start, end, is_const);
+    IrInstruction *new_instruction = ir_build_slice(irb, old_instruction->scope,
+            old_instruction->source_node, ptr, start, end, is_const, safety_check_on);
     ir_link_new_instruction(new_instruction, old_instruction);
     return new_instruction;
 }
@@ -1892,6 +1871,18 @@ static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old
     return new_instruction;
 }
 
+static IrInstruction *ir_build_pointer_reinterpret(IrBuilder *irb, Scope *scope, AstNode *source_node,
+        IrInstruction *ptr)
+{
+    IrInstructionPointerReinterpret *instruction = ir_build_instruction<IrInstructionPointerReinterpret>(
+            irb, scope, source_node);
+    instruction->ptr = ptr;
+
+    ir_ref_instruction(ptr);
+
+    return &instruction->base;
+}
+
 static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
     results[ReturnKindUnconditional] = 0;
     results[ReturnKindError] = 0;
@@ -2088,21 +2079,21 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
             ErrorMsg *msg = add_node_error(codegen, node,
                     buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
             add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
-            variable_entry->type = codegen->builtin_types.entry_invalid;
+            variable_entry->value.type = codegen->builtin_types.entry_invalid;
         } else {
             auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name);
             if (primitive_table_entry) {
                 TypeTableEntry *type = primitive_table_entry->value;
                 add_node_error(codegen, node,
                         buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
-                variable_entry->type = codegen->builtin_types.entry_invalid;
+                variable_entry->value.type = codegen->builtin_types.entry_invalid;
             } else {
                 Tld *tld = find_decl(parent_scope, name);
                 if (tld && tld->id != TldIdVar) {
                     ErrorMsg *msg = add_node_error(codegen, node,
                             buf_sprintf("redefinition of '%s'", buf_ptr(name)));
                     add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
-                    variable_entry->type = codegen->builtin_types.entry_invalid;
+                    variable_entry->value.type = codegen->builtin_types.entry_invalid;
                 }
             }
         }
@@ -3275,7 +3266,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
     // is inside var->child_scope
 
     if (!is_extern && !variable_declaration->expr) {
-        var->type = irb->codegen->builtin_types.entry_invalid;
+        var->value.type = irb->codegen->builtin_types.entry_invalid;
         add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized"));
         return irb->codegen->invalid_instruction;
     }
@@ -3988,7 +3979,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
         end_value = nullptr;
     }
 
-    return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const);
+    return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const, true);
 }
 
 static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -4348,7 +4339,7 @@ static IrInstruction *ir_exec_const_result(IrExecutable *exec) {
         if (instruction->id == IrInstructionIdReturn) {
             IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;
             IrInstruction *value = ret_inst->value;
-            assert(value->static_value.special != ConstValSpecialRuntime);
+            assert(value->value.special != ConstValSpecialRuntime);
             return value;
         } else if (ir_has_side_effects(instruction)) {
             return nullptr;
@@ -4372,7 +4363,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
         return false;
     }
 
-    ConstExprValue *const_val = &instruction->static_value;
+    ConstExprValue *const_val = &instruction->value;
     assert(const_val->special != ConstValSpecialRuntime);
     if (other_type_underlying->id == TypeTableEntryIdFloat) {
         return true;
@@ -4514,15 +4505,15 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
 static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
     assert(instruction_count >= 1);
     IrInstruction *prev_inst = instructions[0];
-    if (prev_inst->type_entry->id == TypeTableEntryIdInvalid) {
+    if (prev_inst->value.type->id == TypeTableEntryIdInvalid) {
         return ira->codegen->builtin_types.entry_invalid;
     }
-    bool any_are_pure_error = (prev_inst->type_entry->id == TypeTableEntryIdPureError);
-    bool any_are_null = (prev_inst->type_entry->id == TypeTableEntryIdNullLit);
+    bool any_are_pure_error = (prev_inst->value.type->id == TypeTableEntryIdPureError);
+    bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);
     for (size_t i = 1; i < instruction_count; i += 1) {
         IrInstruction *cur_inst = instructions[i];
-        TypeTableEntry *cur_type = cur_inst->type_entry;
-        TypeTableEntry *prev_type = prev_inst->type_entry;
+        TypeTableEntry *cur_type = cur_inst->value.type;
+        TypeTableEntry *prev_type = prev_inst->value.type;
         if (cur_type->id == TypeTableEntryIdInvalid) {
             return cur_type;
         } else if (prev_type->id == TypeTableEntryIdUnreachable) {
@@ -4598,32 +4589,32 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
             return ira->codegen->builtin_types.entry_invalid;
         }
     }
-    if (any_are_pure_error && prev_inst->type_entry->id != TypeTableEntryIdPureError) {
-        if (prev_inst->type_entry->id == TypeTableEntryIdNumLitInt ||
-            prev_inst->type_entry->id == TypeTableEntryIdNumLitFloat)
+    if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) {
+        if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
+            prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
         {
             ir_add_error_node(ira, source_node,
                 buf_sprintf("unable to make error union out of number literal"));
             return ira->codegen->builtin_types.entry_invalid;
-        } else if (prev_inst->type_entry->id == TypeTableEntryIdNullLit) {
+        } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
             ir_add_error_node(ira, source_node,
                 buf_sprintf("unable to make error union out of null literal"));
             return ira->codegen->builtin_types.entry_invalid;
         } else {
-            return get_error_type(ira->codegen, prev_inst->type_entry);
+            return get_error_type(ira->codegen, prev_inst->value.type);
         }
-    } else if (any_are_null && prev_inst->type_entry->id != TypeTableEntryIdNullLit) {
-        if (prev_inst->type_entry->id == TypeTableEntryIdNumLitInt ||
-            prev_inst->type_entry->id == TypeTableEntryIdNumLitFloat)
+    } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
+        if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
+            prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
         {
             ir_add_error_node(ira, source_node,
                 buf_sprintf("unable to make maybe out of number literal"));
             return ira->codegen->builtin_types.entry_invalid;
         } else {
-            return get_maybe_type(ira->codegen, prev_inst->type_entry);
+            return get_maybe_type(ira->codegen, prev_inst->value.type);
         }
     } else {
-        return prev_inst->type_entry;
+        return prev_inst->value.type;
     }
 }
 
@@ -4649,9 +4640,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
         case CastOpNoop:
         case CastOpWidenOrShorten:
             *const_val = *other_val;
-            break;
-        case CastOpPointerReinterpret:
-            zig_panic("TODO compile time pointer reinterpret");
+            const_val->type = new_type;
             break;
         case CastOpPtrToInt:
         case CastOpIntToPtr:
@@ -4659,24 +4648,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
         case CastOpBytesToSlice:
             // can't do it
             break;
-        case CastOpToUnknownSizeArray:
-            {
-                assert(other_type->id == TypeTableEntryIdArray);
-                assert(other_val->data.x_array.size == other_type->data.array.len);
-
-                const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
-                ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
-                ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
-
-                ptr_field->special = ConstValSpecialStatic;
-                ptr_field->data.x_ptr.base_ptr = other_val;
-
-                len_field->special = ConstValSpecialStatic;
-                bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
-
-                const_val->special = ConstValSpecialStatic;
-                break;
-            }
         case CastOpErrToInt:
             {
                 uint64_t value;
@@ -4722,14 +4693,15 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
 static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
         TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
 {
-    if (value->static_value.special != ConstValSpecialRuntime) {
-        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, false);
-        eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry,
-                &result->static_value, wanted_type);
+    if (value->value.special != ConstValSpecialRuntime) {
+        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+                source_instr->source_node, wanted_type, false);
+        eval_const_expr_implicit_cast(cast_op, &value->value, value->value.type,
+                &result->value, wanted_type);
         return result;
     } else {
         IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
-        result->type_entry = wanted_type;
+        result->value.type = wanted_type;
         if (need_alloca) {
             FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
             if (fn_entry)
@@ -4861,7 +4833,7 @@ static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_in
         new_instruction = &const_instruction->base;
     }
     ir_link_new_instruction(new_instruction, old_instruction);
-    ConstExprValue *const_val = &new_instruction->static_value;
+    ConstExprValue *const_val = &new_instruction->value;
     const_val->special = ConstValSpecialStatic;
     const_val->depends_on_compile_var = depends_on_compile_var;
     return const_val;
@@ -4906,15 +4878,15 @@ enum UndefAllowed {
 };
 
 static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) {
-    switch (value->static_value.special) {
+    switch (value->value.special) {
         case ConstValSpecialStatic:
-            return &value->static_value;
+            return &value->value;
         case ConstValSpecialRuntime:
             ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
             return nullptr;
         case ConstValSpecialUndef:
             if (undef_allowed == UndefOk) {
-                return &value->static_value;
+                return &value->value;
             } else {
                 ir_add_error(ira, value, buf_sprintf("use of undefined value"));
                 return nullptr;
@@ -4979,12 +4951,12 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
 }
 
 static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
-    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (type_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (type_value->type_entry->id != TypeTableEntryIdMetaType) {
+    if (type_value->value.type->id != TypeTableEntryIdMetaType) {
         ir_add_error(ira, type_value,
-                buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->type_entry->name)));
+                buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 
@@ -4999,12 +4971,12 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
     if (fn_value == ira->codegen->invalid_instruction)
         return nullptr;
 
-    if (fn_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (fn_value->value.type->id == TypeTableEntryIdInvalid)
         return nullptr;
 
-    if (fn_value->type_entry->id != TypeTableEntryIdFn) {
+    if (fn_value->value.type->id != TypeTableEntryIdFn) {
         ir_add_error_node(ira, fn_value->source_node,
-                buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->type_entry->name)));
+                buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->value.type->name)));
         return nullptr;
     }
 
@@ -5019,47 +4991,88 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
     assert(wanted_type->id == TypeTableEntryIdMaybe);
 
     if (instr_is_comptime(value)) {
-        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+        TypeTableEntry *payload_type = wanted_type->data.maybe.child_type;
+        IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
+        if (casted_payload->value.type->id == TypeTableEntryIdInvalid)
+            return ira->codegen->invalid_instruction;
+
+        ConstExprValue *val = ir_resolve_const(ira, casted_payload, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 source_instr->scope, source_instr->source_node);
-        const_instruction->base.type_entry = wanted_type;
-        const_instruction->base.static_value.special = ConstValSpecialStatic;
-        const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-        const_instruction->base.static_value.data.x_maybe = &value->static_value;
+        const_instruction->base.value.type = wanted_type;
+        const_instruction->base.value.special = ConstValSpecialStatic;
+        const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+        const_instruction->base.value.data.x_maybe = val;
         return &const_instruction->base;
     }
 
     IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
-    result->type_entry = wanted_type;
-    result->static_value.data.rh_maybe = RuntimeHintMaybeNonNull;
+    result->value.type = wanted_type;
+    result->value.data.rh_maybe = RuntimeHintMaybeNonNull;
     ir_add_alloca(ira, result, wanted_type);
     return result;
 }
 
-static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+static IrInstruction *ir_analyze_pointer_reinterpret(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *ptr, TypeTableEntry *wanted_type)
+{
+    assert(wanted_type->id == TypeTableEntryIdPointer);
+
+    if (ptr->value.type->id != TypeTableEntryIdPointer) {
+        ir_add_error(ira, ptr,
+            buf_sprintf("expected pointer, found '%s'", buf_ptr(&ptr->value.type->name)));
+        return ira->codegen->invalid_instruction;
+    }
+
+    if (instr_is_comptime(ptr)) {
+        ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
+        if (!val)
+            return ira->codegen->invalid_instruction;
+
+        IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
+                source_instr->scope, source_instr->source_node);
+        const_instruction->base.value = *val;
+        const_instruction->base.value.type = wanted_type;
+        return &const_instruction->base;
+    }
+
+    IrInstruction *result = ir_build_pointer_reinterpret(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, ptr);
+    result->value.type = wanted_type;
+    return result;
+}
+
+static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *value, TypeTableEntry *wanted_type)
+{
     assert(wanted_type->id == TypeTableEntryIdErrorUnion);
 
     if (instr_is_comptime(value)) {
-        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+        TypeTableEntry *payload_type = wanted_type->data.error.child_type;
+        IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
+        if (casted_payload->value.type->id == TypeTableEntryIdInvalid)
+            return ira->codegen->invalid_instruction;
+
+        ConstExprValue *val = ir_resolve_const(ira, casted_payload, UndefBad);
         if (!val)
             return ira->codegen->invalid_instruction;
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 source_instr->scope, source_instr->source_node);
-        const_instruction->base.type_entry = wanted_type;
-        const_instruction->base.static_value.special = ConstValSpecialStatic;
-        const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-        const_instruction->base.static_value.data.x_err_union.err = nullptr;
-        const_instruction->base.static_value.data.x_err_union.payload = val;
+        const_instruction->base.value.type = wanted_type;
+        const_instruction->base.value.special = ConstValSpecialStatic;
+        const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+        const_instruction->base.value.data.x_err_union.err = nullptr;
+        const_instruction->base.value.data.x_err_union.payload = val;
         return &const_instruction->base;
     }
 
     IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
-    result->type_entry = wanted_type;
-    result->static_value.data.rh_error_union = RuntimeHintErrorUnionNonError;
+    result->value.type = wanted_type;
+    result->value.data.rh_error_union = RuntimeHintErrorUnionNonError;
     ir_add_alloca(ira, result, wanted_type);
     return result;
 }
@@ -5074,17 +5087,17 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 source_instr->scope, source_instr->source_node);
-        const_instruction->base.type_entry = wanted_type;
-        const_instruction->base.static_value.special = ConstValSpecialStatic;
-        const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-        const_instruction->base.static_value.data.x_err_union.err = val->data.x_pure_err;
-        const_instruction->base.static_value.data.x_err_union.payload = nullptr;
+        const_instruction->base.value.type = wanted_type;
+        const_instruction->base.value.special = ConstValSpecialStatic;
+        const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+        const_instruction->base.value.data.x_err_union.err = val->data.x_pure_err;
+        const_instruction->base.value.data.x_err_union.payload = nullptr;
         return &const_instruction->base;
     }
 
     IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
-    result->type_entry = wanted_type;
-    result->static_value.data.rh_error_union = RuntimeHintErrorUnionError;
+    result->value.type = wanted_type;
+    result->value.data.rh_error_union = RuntimeHintErrorUnionError;
     ir_add_alloca(ira, result, wanted_type);
     return result;
 }
@@ -5097,11 +5110,11 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 source_instr->scope, source_instr->source_node);
-        const_instruction->base.type_entry = wanted_type;
-        const_instruction->base.static_value.special = ConstValSpecialStatic;
-        const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-        const_instruction->base.static_value.data.x_ptr.base_ptr = val;
-        const_instruction->base.static_value.data.x_ptr.index = SIZE_MAX;
+        const_instruction->base.value.type = wanted_type;
+        const_instruction->base.value.special = ConstValSpecialStatic;
+        const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+        const_instruction->base.value.data.x_ptr.base_ptr = val;
+        const_instruction->base.value.data.x_ptr.index = SIZE_MAX;
         return &const_instruction->base;
     }
 
@@ -5130,17 +5143,48 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
     assert(val);
 
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, source_instr->scope, source_instr->source_node);
-    const_instruction->base.type_entry = wanted_type;
-    const_instruction->base.static_value.special = ConstValSpecialStatic;
-    const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-    const_instruction->base.static_value.data.x_maybe = nullptr;
+    const_instruction->base.value.type = wanted_type;
+    const_instruction->base.value.special = ConstValSpecialStatic;
+    const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+    const_instruction->base.value.data.x_maybe = nullptr;
     return &const_instruction->base;
 }
 
+static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
+        IrInstruction *array, TypeTableEntry *wanted_type)
+{
+    assert(is_slice(wanted_type));
+
+    TypeTableEntry *array_type = array->value.type;
+    assert(array_type->id == TypeTableEntryIdArray);
+
+    if (instr_is_comptime(array)) {
+        IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+                source_instr->source_node, wanted_type, false);
+        init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true);
+        return result;
+    }
+
+    IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, ira->codegen->builtin_types.entry_usize, false);
+    init_const_usize(ira->codegen, &start->value, 0);
+
+    IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, ira->codegen->builtin_types.entry_usize, false);
+    init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
+
+    IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
+            source_instr->source_node, array, start, end, true, false);
+    TypeTableEntry *child_type = array_type->data.array.child_type;
+    result->value.type = get_slice_type(ira->codegen, child_type, true);
+    ir_add_alloca(ira, result, result->value.type);
+    return result;
+}
+
 static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
     TypeTableEntry *wanted_type, IrInstruction *value)
 {
-    TypeTableEntry *actual_type = value->type_entry;
+    TypeTableEntry *actual_type = value->value.type;
     TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
     TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
 
@@ -5213,7 +5257,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
             wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
             actual_type->data.array.child_type))
     {
-        return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpToUnknownSizeArray, true);
+        return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
     }
 
     // explicit cast from []T to []u8 or []u8 to []T
@@ -5251,7 +5295,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
     if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
         (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
     {
-        return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false);
+        return ir_analyze_pointer_reinterpret(ira, source_instr, value, wanted_type);
     }
 
     // explicit cast from maybe pointer to another maybe pointer
@@ -5262,7 +5306,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         (wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
             wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
     {
-        return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false);
+        return ir_analyze_pointer_reinterpret(ira, source_instr, value, wanted_type);
     }
 
     // explicit cast from child type of maybe type to maybe type
@@ -5394,22 +5438,22 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
     assert(value);
     assert(value != ira->codegen->invalid_instruction);
     assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
-    assert(value->type_entry);
-    assert(value->type_entry->id != TypeTableEntryIdInvalid);
+    assert(value->value.type);
+    assert(value->value.type->id != TypeTableEntryIdInvalid);
     if (expected_type == nullptr)
         return value; // anything will do
-    if (expected_type == value->type_entry)
+    if (expected_type == value->value.type)
         return value; // match
-    if (value->type_entry->id == TypeTableEntryIdUnreachable)
+    if (value->value.type->id == TypeTableEntryIdUnreachable)
         return value;
 
-    ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->type_entry, value);
+    ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value);
     switch (result) {
         case ImplicitCastMatchResultNo:
             ir_add_error(ira, value,
                 buf_sprintf("expected type '%s', found '%s'",
                     buf_ptr(&expected_type->name),
-                    buf_ptr(&value->type_entry->name)));
+                    buf_ptr(&value->value.type->name)));
             return ira->codegen->invalid_instruction;
 
         case ImplicitCastMatchResultYes:
@@ -5422,23 +5466,23 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
 }
 
 static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
-    TypeTableEntry *type_entry = ptr->type_entry;
+    TypeTableEntry *type_entry = ptr->value.type;
     if (type_entry->id == TypeTableEntryIdInvalid) {
         return ira->codegen->invalid_instruction;
     } else if (type_entry->id == TypeTableEntryIdPointer) {
         TypeTableEntry *child_type = type_entry->data.pointer.child_type;
-        if (ptr->static_value.special != ConstValSpecialRuntime) {
-            ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value);
+        if (ptr->value.special != ConstValSpecialRuntime) {
+            ConstExprValue *pointee = const_ptr_pointee(&ptr->value);
             if (pointee->special != ConstValSpecialRuntime) {
                 IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
                     source_instruction->source_node, child_type, pointee->depends_on_compile_var);
-                result->static_value = *pointee;
+                result->value = *pointee;
                 return result;
             }
         }
         // TODO if the instruction is a get pointer instruction we can skip it
         IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr);
-        load_ptr_instruction->type_entry = child_type;
+        load_ptr_instruction->value.type = child_type;
         return load_ptr_instruction;
     } else if (type_entry->id == TypeTableEntryIdMetaType) {
         ConstExprValue *ptr_val = ir_resolve_const(ira, ptr, UndefBad);
@@ -5465,18 +5509,18 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
 static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
         bool is_const)
 {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     if (instr_is_comptime(value)) {
         ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
         if (!val)
             return ira->codegen->builtin_types.entry_invalid;
-        return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry,
+        return ir_analyze_const_ptr(ira, source_instruction, val, value->value.type,
                 false, ConstPtrSpecialNone, is_const);
     }
 
-    TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
+    TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->value.type, true);
     FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
     assert(fn_entry);
     IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value, is_const);
@@ -5485,11 +5529,11 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst
 }
 
 static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_usize);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
@@ -5501,11 +5545,11 @@ static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out
 }
 
 static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_bool);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
@@ -5517,11 +5561,11 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
 }
 
 static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_atomic_order_enum);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
@@ -5533,12 +5577,12 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
 }
 
 static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return nullptr;
 
     TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
     IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return nullptr;
 
     ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
@@ -5567,7 +5611,7 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
     IrInstructionReturn *return_instruction)
 {
     IrInstruction *value = return_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ir_unreach_error(ira);
     ira->implicit_return_type_list.append(value);
 
@@ -5580,19 +5624,19 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
 }
 
 static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) {
-    bool depends_on_compile_var = const_instruction->base.static_value.depends_on_compile_var;
+    bool depends_on_compile_var = const_instruction->base.value.depends_on_compile_var;
     ConstExprValue *out_val = ir_build_const_from(ira, &const_instruction->base, depends_on_compile_var);
-    *out_val = const_instruction->base.static_value;
-    return const_instruction->base.type_entry;
+    *out_val = const_instruction->base.value;
+    return const_instruction->base.value.type;
 }
 
 static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
     IrInstruction *op1 = bin_op_instruction->op1->other;
-    if (op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *op2 = bin_op_instruction->op2->other;
-    if (op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
@@ -5605,14 +5649,14 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
     if (casted_op2 == ira->codegen->invalid_instruction)
         return ira->codegen->builtin_types.entry_invalid;
 
-    ConstExprValue *op1_val = &casted_op1->static_value;
-    ConstExprValue *op2_val = &casted_op2->static_value;
+    ConstExprValue *op1_val = &casted_op1->value;
+    ConstExprValue *op2_val = &casted_op2->value;
     if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) {
         bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var);
 
-        assert(casted_op1->type_entry->id == TypeTableEntryIdBool);
-        assert(casted_op2->type_entry->id == TypeTableEntryIdBool);
+        assert(casted_op1->value.type->id == TypeTableEntryIdBool);
+        assert(casted_op2->value.type->id == TypeTableEntryIdBool);
         if (bin_op_instruction->op_id == IrBinOpBoolOr) {
             out_val->data.x_bool = op1_val->data.x_bool || op2_val->data.x_bool;
         } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) {
@@ -5701,8 +5745,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
     if (casted_op2 == ira->codegen->invalid_instruction)
         return ira->codegen->builtin_types.entry_invalid;
 
-    ConstExprValue *op1_val = &casted_op1->static_value;
-    ConstExprValue *op2_val = &casted_op2->static_value;
+    ConstExprValue *op1_val = &casted_op1->value;
+    ConstExprValue *op2_val = &casted_op2->value;
     if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) {
         bool type_can_gt_lt_cmp = (resolved_type->id == TypeTableEntryIdNumLitFloat ||
                 resolved_type->id == TypeTableEntryIdNumLitInt ||
@@ -5729,7 +5773,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
 
             answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
         } else {
-            bool are_equal = const_values_equal(op1_val, op2_val, resolved_type);
+            bool are_equal = const_values_equal(op1_val, op2_val);
             if (op_id == IrBinOpCmpEq) {
                 answer = are_equal;
             } else if (op_id == IrBinOpCmpNotEq) {
@@ -5872,8 +5916,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
         AstNode *source_node = bin_op_instruction->base.source_node;
         ir_add_error_node(ira, source_node,
             buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
-                buf_ptr(&op1->type_entry->name),
-                buf_ptr(&op2->type_entry->name)));
+                buf_ptr(&op1->value.type->name),
+                buf_ptr(&op2->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 
@@ -5886,10 +5930,10 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
         return ira->codegen->builtin_types.entry_invalid;
 
 
-    if (casted_op1->static_value.special != ConstValSpecialRuntime && casted_op2->static_value.special != ConstValSpecialRuntime) {
-        ConstExprValue *op1_val = &casted_op1->static_value;
-        ConstExprValue *op2_val = &casted_op2->static_value;
-        ConstExprValue *out_val = &bin_op_instruction->base.static_value;
+    if (casted_op1->value.special != ConstValSpecialRuntime && casted_op2->value.special != ConstValSpecialRuntime) {
+        ConstExprValue *op1_val = &casted_op1->value;
+        ConstExprValue *op2_val = &casted_op2->value;
+        ConstExprValue *out_val = &bin_op_instruction->base.value;
 
         bin_op_instruction->base.other = &bin_op_instruction->base;
 
@@ -5919,12 +5963,12 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
 
 static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruction) {
     IrInstruction *op1 = instruction->op1->other;
-    TypeTableEntry *op1_canon_type = get_underlying_type(op1->type_entry);
+    TypeTableEntry *op1_canon_type = get_underlying_type(op1->value.type);
     if (op1_canon_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *op2 = instruction->op2->other;
-    TypeTableEntry *op2_canon_type = get_underlying_type(op2->type_entry);
+    TypeTableEntry *op2_canon_type = get_underlying_type(op2->value.type);
     if (op2_canon_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
@@ -5955,7 +5999,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
         op1_array_end = op1_array_val->data.x_array.size - 1;
     } else {
         ir_add_error(ira, op1,
-            buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->type_entry->name)));
+            buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name)));
         // TODO if meta_type is type decl, add note pointing to type decl declaration
         return ira->codegen->builtin_types.entry_invalid;
     }
@@ -5967,7 +6011,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
         if (op2_canon_type->data.array.child_type != child_type) {
             ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
                         buf_ptr(&child_type->name),
-                        buf_ptr(&op2->type_entry->name)));
+                        buf_ptr(&op2->value.type->name)));
             return ira->codegen->builtin_types.entry_invalid;
         }
         op2_array_val = op2_val;
@@ -5980,7 +6024,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
         if (child_type != ira->codegen->builtin_types.entry_u8) {
             ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'",
                         buf_ptr(&child_type->name),
-                        buf_ptr(&op2->type_entry->name)));
+                        buf_ptr(&op2->value.type->name)));
             return ira->codegen->builtin_types.entry_invalid;
         }
         op2_array_val = op2_val->data.x_ptr.base_ptr;
@@ -5988,12 +6032,12 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
         op2_array_end = op2_array_val->data.x_array.size - 1;
     } else {
         ir_add_error(ira, op2,
-            buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->type_entry->name)));
+            buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name)));
         // TODO if meta_type is type decl, add note pointing to type decl declaration
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    bool depends_on_compile_var = op1->static_value.depends_on_compile_var || op2->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = op1->value.depends_on_compile_var || op2->value.depends_on_compile_var;
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
 
     TypeTableEntry *result_type;
@@ -6008,6 +6052,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
 
         out_array_val = allocate<ConstExprValue>(1);
         out_array_val->special = ConstValSpecialStatic;
+        out_array_val->type = result_type;
         out_val->data.x_ptr.base_ptr = out_array_val;
         out_val->data.x_ptr.index = 0;
         out_val->data.x_ptr.special = ConstPtrSpecialCStr;
@@ -6026,8 +6071,7 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
     }
     if (next_index < new_len) {
         ConstExprValue *null_byte = &out_array_val->data.x_array.elements[next_index];
-        null_byte->special = ConstValSpecialStatic;
-        bignum_init_unsigned(&null_byte->data.x_bignum, 0);
+        init_const_unsigned_negative(null_byte, child_type, 0, false);
         next_index += 1;
     }
     assert(next_index == new_len);
@@ -6037,11 +6081,11 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
 
 static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp *instruction) {
     IrInstruction *op1 = instruction->op1->other;
-    if (op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *op2 = instruction->op2->other;
-    if (op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     ConstExprValue *array_val = ir_resolve_const(ira, op1, UndefBad);
@@ -6052,9 +6096,9 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
     if (!ir_resolve_usize(ira, op2, &mult_amt))
         return ira->codegen->builtin_types.entry_invalid;
 
-    TypeTableEntry *array_canon_type = get_underlying_type(op1->type_entry);
+    TypeTableEntry *array_canon_type = get_underlying_type(op1->value.type);
     if (array_canon_type->id != TypeTableEntryIdArray) {
-        ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->type_entry->name)));
+        ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value.type->name)));
         // TODO if meta_type is type decl, add note pointing to type decl declaration
         return ira->codegen->builtin_types.entry_invalid;
     }
@@ -6068,7 +6112,7 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    bool depends_on_compile_var = op1->static_value.depends_on_compile_var || op2->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = op1->value.depends_on_compile_var || op2->value.depends_on_compile_var;
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
 
     uint64_t new_array_len = array_len.data.x_uint;
@@ -6130,9 +6174,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
     VariableTableEntry *var = decl_var_instruction->var;
 
     IrInstruction *init_value = decl_var_instruction->init_value->other;
-    if (init_value->type_entry->id == TypeTableEntryIdInvalid) {
-        var->type = ira->codegen->builtin_types.entry_invalid;
-        return var->type;
+    if (init_value->value.type->id == TypeTableEntryIdInvalid) {
+        var->value.type = ira->codegen->builtin_types.entry_invalid;
+        return var->value.type;
     }
 
     AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration;
@@ -6148,15 +6192,15 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
         TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type);
         explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
         if (explicit_type->id == TypeTableEntryIdInvalid) {
-            var->type = ira->codegen->builtin_types.entry_invalid;
-            return var->type;
+            var->value.type = ira->codegen->builtin_types.entry_invalid;
+            return var->value.type;
         }
     }
 
     AstNode *source_node = decl_var_instruction->base.source_node;
 
     IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
-    TypeTableEntry *result_type = get_underlying_type(casted_init_value->type_entry);
+    TypeTableEntry *result_type = get_underlying_type(casted_init_value->value.type);
     switch (result_type->id) {
         case TypeTableEntryIdTypeDecl:
             zig_unreachable();
@@ -6165,7 +6209,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
             break;
         case TypeTableEntryIdNumLitFloat:
         case TypeTableEntryIdNumLitInt:
-            if (is_export || is_extern || casted_init_value->static_value.special == ConstValSpecialRuntime) {
+            if (is_export || is_extern || casted_init_value->value.special == ConstValSpecialRuntime) {
                 ir_add_error_node(ira, source_node, buf_sprintf("unable to infer variable type"));
                 result_type = ira->codegen->builtin_types.entry_invalid;
             }
@@ -6180,7 +6224,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
             break;
         case TypeTableEntryIdMetaType:
         case TypeTableEntryIdNamespace:
-            if (casted_init_value->static_value.special == ConstValSpecialRuntime) {
+            if (casted_init_value->value.special == ConstValSpecialRuntime) {
                 ir_add_error_node(ira, source_node,
                     buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name)));
                 result_type = ira->codegen->builtin_types.entry_invalid;
@@ -6206,16 +6250,16 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
             break;
     }
 
-    var->type = result_type;
-    assert(var->type);
+    var->value.type = result_type;
+    assert(var->value.type);
 
     bool is_comptime = ir_get_var_is_comptime(var);
 
-    if (casted_init_value->static_value.special != ConstValSpecialRuntime) {
+    if (casted_init_value->value.special != ConstValSpecialRuntime) {
         if (var->mem_slot_index != SIZE_MAX) {
             assert(var->mem_slot_index < ira->exec_context.mem_slot_count);
             ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
-            *mem_slot = casted_init_value->static_value;
+            *mem_slot = casted_init_value->value;
 
             if (is_comptime) {
                 ir_build_const_from(ira, &decl_var_instruction->base, false);
@@ -6225,7 +6269,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
     } else if (is_comptime) {
         ir_add_error(ira, &decl_var_instruction->base,
                 buf_sprintf("cannot store runtime value in compile time variable"));
-        var->type = ira->codegen->builtin_types.entry_invalid;
+        var->value.type = ira->codegen->builtin_types.entry_invalid;
         return ira->codegen->builtin_types.entry_invalid;
     }
 
@@ -6249,7 +6293,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
         return false;
 
     IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type);
-    if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     ConstExprValue *first_arg_val = ir_resolve_const(ira, casted_arg, UndefBad);
@@ -6258,7 +6302,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
 
     Buf *param_name = param_decl_node->data.param_decl.name;
     VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
-        *exec_scope, param_name, casted_arg->type_entry, true, first_arg_val);
+        *exec_scope, param_name, true, first_arg_val);
     *exec_scope = var->child_scope;
     *next_proto_i += 1;
 
@@ -6278,7 +6322,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
         return false;
 
     IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type);
-    if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
         return false;
 
     bool inline_arg = param_decl_node->data.param_decl.is_inline;
@@ -6294,24 +6338,22 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
         // needs to know that it depends on compile time variable data.
         arg_val->depends_on_compile_var = true;
     } else {
-        arg_val = nullptr;
+        arg_val = create_const_runtime(casted_arg->value.type);
     }
 
     Buf *param_name = param_decl_node->data.param_decl.name;
     VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
-        *child_scope, param_name, casted_arg->type_entry, true, arg_val);
+        *child_scope, param_name, true, arg_val);
     *child_scope = var->child_scope;
 
     if (inline_arg || is_var_type) {
-        GenericParamValue *generic_param = &generic_id->params[generic_id->param_count];
-        generic_param->type = casted_arg->type_entry;
-        generic_param->value = arg_val;
+        generic_id->params[generic_id->param_count] = *arg_val;
         generic_id->param_count += 1;
     }
     if (!inline_arg) {
-        if (type_requires_comptime(var->type)) {
+        if (type_requires_comptime(var->value.type)) {
             ir_add_error(ira, arg,
-                buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->type->name)));
+                buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->value.type->name)));
             return false;
         }
 
@@ -6319,7 +6361,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
 
         casted_args[fn_type_id->param_count] = casted_arg;
         FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count];
-        param_info->type = casted_arg->type_entry;
+        param_info->type = casted_arg->value.type;
         param_info->is_noalias = param_decl_node->data.param_decl.is_noalias;
         impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node;
         fn_type_id->param_count += 1;
@@ -6376,7 +6418,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         size_t next_proto_i = 0;
         if (first_arg_ptr) {
             IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
-            if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
+            if (first_arg->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, first_arg, &exec_scope, &next_proto_i))
@@ -6385,7 +6427,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
 
         for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
             IrInstruction *old_arg = call_instruction->args[call_i]->other;
-            if (old_arg->type_entry->id == TypeTableEntryIdInvalid)
+            if (old_arg->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i))
@@ -6408,15 +6450,15 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
             result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
                 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
                 nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
-            if (result->type_entry->id == TypeTableEntryIdInvalid)
+            if (result->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
         }
 
         ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,
-                result->static_value.depends_on_compile_var);
-        *out_val = result->static_value;
+                result->value.depends_on_compile_var);
+        *out_val = result->value;
         return ir_finish_anal(ira, return_type);
     }
 
@@ -6441,12 +6483,12 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         GenericFnTypeId *generic_id = allocate<GenericFnTypeId>(1);
         generic_id->fn_entry = fn_entry;
         generic_id->param_count = 0;
-        generic_id->params = allocate<GenericParamValue>(src_param_count);
+        generic_id->params = allocate<ConstExprValue>(src_param_count);
         size_t next_proto_i = 0;
 
         if (first_arg_ptr) {
             IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
-            if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
+            if (first_arg->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, first_arg, &impl_fn->child_scope,
@@ -6457,7 +6499,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
         }
         for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
             IrInstruction *arg = call_instruction->args[call_i]->other;
-            if (arg->type_entry->id == TypeTableEntryIdInvalid)
+            if (arg->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             if (!ir_analyze_fn_call_generic_arg(ira, fn_proto_node, arg, &impl_fn->child_scope,
@@ -6513,7 +6555,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
     size_t next_arg_index = 0;
     if (first_arg_ptr) {
         IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
-        if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
+        if (first_arg->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
         TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
@@ -6521,7 +6563,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
             return ira->codegen->builtin_types.entry_invalid;
 
         IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
-        if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+        if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
         casted_args[next_arg_index] = casted_arg;
@@ -6529,7 +6571,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
     }
     for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
         IrInstruction *old_arg = call_instruction->args[call_i]->other;
-        if (old_arg->type_entry->id == TypeTableEntryIdInvalid)
+        if (old_arg->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
         IrInstruction *casted_arg;
         if (next_arg_index < src_param_count) {
@@ -6537,7 +6579,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
             if (param_type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
             casted_arg = ir_implicit_cast(ira, old_arg, param_type);
-            if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+            if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
         } else {
             casted_arg = old_arg;
@@ -6562,13 +6604,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
 
 static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
     IrInstruction *fn_ref = call_instruction->fn_ref->other;
-    if (fn_ref->type_entry->id == TypeTableEntryIdInvalid)
+    if (fn_ref->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     bool is_inline = call_instruction->is_inline || ir_should_inline(&ira->new_irb);
 
-    if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) {
-        if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
+    if (is_inline || fn_ref->value.special != ConstValSpecialRuntime) {
+        if (fn_ref->value.type->id == TypeTableEntryIdMetaType) {
             TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref);
             if (dest_type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
@@ -6584,34 +6626,34 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
             IrInstruction *arg = call_instruction->args[0]->other;
 
             IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg);
-            if (cast_instruction->type_entry->id == TypeTableEntryIdInvalid)
+            if (cast_instruction->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
             ir_link_new_instruction(cast_instruction, &call_instruction->base);
-            return ir_finish_anal(ira, cast_instruction->type_entry);
-        } else if (fn_ref->type_entry->id == TypeTableEntryIdFn) {
+            return ir_finish_anal(ira, cast_instruction->value.type);
+        } else if (fn_ref->value.type->id == TypeTableEntryIdFn) {
             FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
             return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
                 fn_ref, nullptr, is_inline);
-        } else if (fn_ref->type_entry->id == TypeTableEntryIdBoundFn) {
-            assert(fn_ref->static_value.special == ConstValSpecialStatic);
-            FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_bound_fn.fn;
-            IrInstruction *first_arg_ptr = fn_ref->static_value.data.x_bound_fn.first_arg;
+        } else if (fn_ref->value.type->id == TypeTableEntryIdBoundFn) {
+            assert(fn_ref->value.special == ConstValSpecialStatic);
+            FnTableEntry *fn_table_entry = fn_ref->value.data.x_bound_fn.fn;
+            IrInstruction *first_arg_ptr = fn_ref->value.data.x_bound_fn.first_arg;
             return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
                 nullptr, first_arg_ptr, is_inline);
         } else {
             ir_add_error_node(ira, fn_ref->source_node,
-                buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name)));
+                buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
             return ira->codegen->builtin_types.entry_invalid;
         }
     }
 
-    if (fn_ref->type_entry->id == TypeTableEntryIdFn) {
-        return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->type_entry,
+    if (fn_ref->value.type->id == TypeTableEntryIdFn) {
+        return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value.type,
             fn_ref, nullptr, false);
     } else {
         ir_add_error_node(ira, fn_ref->source_node,
-            buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name)));
+            buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 }
@@ -6620,10 +6662,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
     assert(un_op_instruction->op_id == IrUnOpError);
     IrInstruction *value = un_op_instruction->value->other;
 
-    TypeTableEntry *type_entry = value->type_entry;
-    if (type_entry->id == TypeTableEntryIdInvalid)
-        return ira->codegen->builtin_types.entry_invalid;
-
     TypeTableEntry *meta_type = ir_resolve_type(ira, value);
     TypeTableEntry *underlying_meta_type = get_underlying_type(meta_type);
     switch (underlying_meta_type->id) {
@@ -6648,7 +6686,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
         case TypeTableEntryIdEnumTag:
             {
                 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
-                        value->static_value.depends_on_compile_var);
+                        value->value.depends_on_compile_var);
                 TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
                 out_val->data.x_type = result_type;
                 return ira->codegen->builtin_types.entry_type;
@@ -6674,7 +6712,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
 static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
     IrInstruction *value = un_op_instruction->value->other;
 
-    TypeTableEntry *ptr_type = value->type_entry;
+    TypeTableEntry *ptr_type = value->value.type;
     TypeTableEntry *child_type;
     if (ptr_type->id == TypeTableEntryIdInvalid) {
         return ira->codegen->builtin_types.entry_invalid;
@@ -6690,9 +6728,9 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
     // this dereference is always an rvalue because in the IR gen we identify lvalue and emit
     // one of the ptr instructions
 
-    if (value->static_value.special != ConstValSpecialRuntime) {
+    if (value->value.special != ConstValSpecialRuntime) {
         ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, false);
-        ConstExprValue *pointee = const_ptr_pointee(&value->static_value);
+        ConstExprValue *pointee = const_ptr_pointee(&value->value);
         *out_val = *pointee;
         return child_type;
     }
@@ -6735,7 +6773,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
         case TypeTableEntryIdEnumTag:
             {
                 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
-                        value->static_value.depends_on_compile_var);
+                        value->value.depends_on_compile_var);
                 out_val->data.x_type = get_maybe_type(ira->codegen, type_entry);
                 return ira->codegen->builtin_types.entry_type;
             }
@@ -6750,7 +6788,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
 
 static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
     IrInstruction *value = un_op_instruction->value->other;
-    TypeTableEntry *expr_type = value->type_entry;
+    TypeTableEntry *expr_type = value->value.type;
     if (expr_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
@@ -6765,7 +6803,7 @@ static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un
             if (!target_const_val)
                 return ira->codegen->builtin_types.entry_invalid;
 
-            bool depends_on_compile_var = value->static_value.depends_on_compile_var;
+            bool depends_on_compile_var = value->value.depends_on_compile_var;
             ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var);
             bignum_negate(&out_val->data.x_bignum, &target_const_val->data.x_bignum);
             if (expr_type->id == TypeTableEntryIdFloat ||
@@ -6846,7 +6884,7 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr
 
 static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
     IrInstruction *condition = cond_br_instruction->condition->other;
-    if (condition->type_entry->id == TypeTableEntryIdInvalid)
+    if (condition->value.type->id == TypeTableEntryIdInvalid)
         return ir_unreach_error(ira);
 
     bool is_comptime;
@@ -6891,18 +6929,18 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
             if (predecessor != ira->const_predecessor_bb)
                 continue;
             IrInstruction *value = phi_instruction->incoming_values[i]->other;
-            assert(value->type_entry);
-            if (value->type_entry->id == TypeTableEntryIdInvalid)
+            assert(value->value.type);
+            if (value->value.type->id == TypeTableEntryIdInvalid)
                 return ira->codegen->builtin_types.entry_invalid;
 
-            if (value->static_value.special != ConstValSpecialRuntime) {
+            if (value->value.special != ConstValSpecialRuntime) {
                 ConstExprValue *out_val = ir_build_const_from(ira, &phi_instruction->base,
-                        value->static_value.depends_on_compile_var);
-                *out_val = value->static_value;
+                        value->value.depends_on_compile_var);
+                *out_val = value->value;
             } else {
                 phi_instruction->base.other = value;
             }
-            return value->type_entry;
+            return value->value.type;
         }
         zig_unreachable();
     }
@@ -6919,10 +6957,10 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
         IrInstruction *old_value = phi_instruction->incoming_values[i];
         assert(old_value);
         IrInstruction *new_value = old_value->other;
-        if (!new_value || new_value->type_entry->id == TypeTableEntryIdUnreachable)
+        if (!new_value || new_value->value.type->id == TypeTableEntryIdUnreachable)
             continue;
 
-        if (new_value->type_entry->id == TypeTableEntryIdInvalid)
+        if (new_value->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
 
@@ -6935,7 +6973,7 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
     if (new_incoming_blocks.length == 1) {
         IrInstruction *first_value = new_incoming_values.at(0);
         phi_instruction->base.other = first_value;
-        return first_value->type_entry;
+        return first_value->value.type;
     }
 
     TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node,
@@ -6973,16 +7011,16 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
 }
 
 static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var) {
-    assert(var->type);
-    if (var->type->id == TypeTableEntryIdInvalid)
-        return var->type;
+    assert(var->value.type);
+    if (var->value.type->id == TypeTableEntryIdInvalid)
+        return var->value.type;
 
     bool is_comptime = ir_get_var_is_comptime(var);
 
     ConstExprValue *mem_slot = nullptr;
     FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
-    if (var->src_is_const && var->value) {
-        mem_slot = var->value;
+    if (var->src_is_const && var->value.special == ConstValSpecialStatic) {
+        mem_slot = &var->value;
         assert(mem_slot->special != ConstValSpecialRuntime);
     } else if (fn_entry) {
         // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
@@ -6992,10 +7030,10 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
 
     if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
         ConstPtrSpecial ptr_special = is_comptime ? ConstPtrSpecialInline : ConstPtrSpecialNone;
-        return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special, var->src_is_const);
+        return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type, false, ptr_special, var->src_is_const);
     } else {
         ir_build_var_ptr_from(&ira->new_irb, instruction, var);
-        return get_pointer_to_type(ira->codegen, var->type, var->src_is_const);
+        return get_pointer_to_type(ira->codegen, var->value.type, var->src_is_const);
     }
 }
 
@@ -7006,15 +7044,15 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
 
 static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
     IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other;
-    if (array_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (array_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;
-    if (elem_index->type_entry->id == TypeTableEntryIdInvalid)
+    if (elem_index->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     // This will be a pointer type because elem ptr IR instruction operates on a pointer to a thing.
-    TypeTableEntry *ptr_type = array_ptr->type_entry;
+    TypeTableEntry *ptr_type = array_ptr->value.type;
     assert(ptr_type->id == TypeTableEntryIdPointer);
 
     TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
@@ -7045,8 +7083,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
         return ira->codegen->builtin_types.entry_invalid;
 
     bool safety_check_on = elem_ptr_instruction->safety_check_on;
-    if (casted_elem_index->static_value.special != ConstValSpecialRuntime) {
-        uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint;
+    if (casted_elem_index->value.special != ConstValSpecialRuntime) {
+        uint64_t index = casted_elem_index->value.data.x_bignum.data.x_uint;
         if (array_type->id == TypeTableEntryIdArray) {
             uint64_t array_len = array_type->data.array.len;
             if (index >= array_len) {
@@ -7059,12 +7097,12 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
         }
 
         ConstExprValue *array_ptr_val;
-        if (array_ptr->static_value.special != ConstValSpecialRuntime &&
-            (array_ptr_val = const_ptr_pointee(&array_ptr->static_value)) &&
+        if (array_ptr->value.special != ConstValSpecialRuntime &&
+            (array_ptr_val = const_ptr_pointee(&array_ptr->value)) &&
             array_ptr_val->special != ConstValSpecialRuntime)
         {
             bool depends_on_compile_var = array_ptr_val->depends_on_compile_var ||
-                casted_elem_index->static_value.depends_on_compile_var;
+                casted_elem_index->value.depends_on_compile_var;
             ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var);
             if (array_type->id == TypeTableEntryIdPointer) {
                 size_t offset = array_ptr_val->data.x_ptr.index;
@@ -7136,7 +7174,7 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
                 return ira->codegen->builtin_types.entry_invalid;
             TldFn *tld_fn = (TldFn *)tld;
             FnTableEntry *fn_entry = tld_fn->fn_entry;
-            bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
+            bool depends_on_compile_var = container_ptr->value.depends_on_compile_var;
             IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, field_ptr_instruction->base.scope,
                 field_ptr_instruction->base.source_node, fn_entry, container_ptr, depends_on_compile_var);
             return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true);
@@ -7206,6 +7244,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             // the same one every time
             ConstExprValue *const_val = allocate<ConstExprValue>(1);
             const_val->special = ConstValSpecialStatic;
+            const_val->type = fn_entry->type_entry;
             const_val->data.x_fn = fn_entry;
 
             bool ptr_is_const = true;
@@ -7221,6 +7260,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             // the same one every time
             ConstExprValue *const_val = allocate<ConstExprValue>(1);
             const_val->special = ConstValSpecialStatic;
+            const_val->type = ira->codegen->builtin_types.entry_type;
             const_val->data.x_type = tld_typedef->type_entry;
 
             bool ptr_is_const = true;
@@ -7233,26 +7273,26 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
 
 static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {
     IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;
-    if (container_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (container_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *container_type;
-    if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
-        container_type = container_ptr->type_entry->data.pointer.child_type;
-    } else if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
-        container_type = container_ptr->type_entry;
+    if (container_ptr->value.type->id == TypeTableEntryIdPointer) {
+        container_type = container_ptr->value.type->data.pointer.child_type;
+    } else if (container_ptr->value.type->id == TypeTableEntryIdMetaType) {
+        container_type = container_ptr->value.type;
     } else {
         zig_unreachable();
     }
 
-    bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = container_ptr->value.depends_on_compile_var;
     Buf *field_name = field_ptr_instruction->field_name;
     AstNode *source_node = field_ptr_instruction->base.source_node;
 
     if (container_type->id == TypeTableEntryIdInvalid) {
         return container_type;
     } else if (is_container_ref(container_type)) {
-        assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
+        assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
         if (container_type->id == TypeTableEntryIdPointer) {
             TypeTableEntry *bare_type = container_ref_type(container_type);
             IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr);
@@ -7263,8 +7303,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
     } else if (container_type->id == TypeTableEntryIdArray) {
         if (buf_eql_str(field_name, "len")) {
             ConstExprValue *len_val = allocate<ConstExprValue>(1);
-            len_val->special = ConstValSpecialStatic;
-            bignum_init_unsigned(&len_val->data.x_bignum, container_type->data.array.len);
+            init_const_usize(ira->codegen, len_val, container_type->data.array.len);
 
             TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
             bool ptr_is_const = true;
@@ -7282,11 +7321,11 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
 
         TypeTableEntry *child_type;
-        if (container_ptr->type_entry->id == TypeTableEntryIdMetaType) {
+        if (container_ptr->value.type->id == TypeTableEntryIdMetaType) {
             TypeTableEntry *ptr_type = container_ptr_val->data.x_type;
             assert(ptr_type->id == TypeTableEntryIdPointer);
             child_type = ptr_type->data.pointer.child_type;
-        } else if (container_ptr->type_entry->id == TypeTableEntryIdPointer) {
+        } else if (container_ptr->value.type->id == TypeTableEntryIdPointer) {
             ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
             child_type = child_val->data.x_type;
         } else {
@@ -7303,14 +7342,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
                     if (field->type_entry->id == TypeTableEntryIdVoid) {
                         bool ptr_is_const = true;
                         return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
-                                create_const_enum_tag(field->value), child_type, depends_on_compile_var,
+                                create_const_enum_tag(child_type, field->value), child_type, depends_on_compile_var,
                                 ConstPtrSpecialNone, ptr_is_const);
                     } else {
                         bool ptr_is_const = true;
                         return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
-                                create_const_unsigned_negative(field->value, false),
-                                child_type->data.enumeration.tag_type, depends_on_compile_var,
-                                ConstPtrSpecialNone, ptr_is_const);
+                            create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false),
+                            child_type->data.enumeration.tag_type, depends_on_compile_var,
+                            ConstPtrSpecialNone, ptr_is_const);
                     }
                 }
             }
@@ -7329,6 +7368,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             if (err_table_entry) {
                 ConstExprValue *const_val = allocate<ConstExprValue>(1);
                 const_val->special = ConstValSpecialStatic;
+                const_val->type = child_type;
                 const_val->data.x_pure_err = err_table_entry->value;
 
                 bool ptr_is_const = true;
@@ -7343,13 +7383,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             if (buf_eql_str(field_name, "bit_count")) {
                 bool ptr_is_const = true;
                 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
-                    create_const_unsigned_negative(child_type->data.integral.bit_count, false),
+                    create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int,
+                        child_type->data.integral.bit_count, false),
                     ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var,
                     ConstPtrSpecialNone, ptr_is_const);
             } else if (buf_eql_str(field_name, "is_signed")) {
                 bool ptr_is_const = true;
                 return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
-                    create_const_bool(child_type->data.integral.is_signed),
+                    create_const_bool(ira->codegen, child_type->data.integral.is_signed),
                     ira->codegen->builtin_types.entry_bool, depends_on_compile_var,
                     ConstPtrSpecialNone, ptr_is_const);
             } else {
@@ -7364,7 +7405,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
         }
     } else if (container_type->id == TypeTableEntryIdNamespace) {
-        assert(container_ptr->type_entry->id == TypeTableEntryIdPointer);
+        assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
         ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
         if (!container_ptr_val)
             return ira->codegen->builtin_types.entry_invalid;
@@ -7414,30 +7455,30 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc
     IrInstruction *ptr = load_ptr_instruction->ptr->other;
     IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr);
     ir_link_new_instruction(result, &load_ptr_instruction->base);
-    assert(result->type_entry);
-    return result->type_entry;
+    assert(result->value.type);
+    return result->value.type;
 }
 
 static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
     IrInstruction *ptr = store_ptr_instruction->ptr->other;
-    if (ptr->type_entry->id == TypeTableEntryIdInvalid)
-        return ptr->type_entry;
+    if (ptr->value.type->id == TypeTableEntryIdInvalid)
+        return ptr->value.type;
 
     IrInstruction *value = store_ptr_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
-        return value->type_entry;
+    if (value->value.type->id == TypeTableEntryIdInvalid)
+        return value->value.type;
 
-    TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type;
+    TypeTableEntry *child_type = ptr->value.type->data.pointer.child_type;
     IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
     if (casted_value == ira->codegen->invalid_instruction)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (ptr->static_value.special != ConstValSpecialRuntime) {
-        bool is_inline = (ptr->static_value.data.x_ptr.special == ConstPtrSpecialInline);
-        if (casted_value->static_value.special != ConstValSpecialRuntime) {
-            ConstExprValue *dest_val = const_ptr_pointee(&ptr->static_value);
+    if (ptr->value.special != ConstValSpecialRuntime) {
+        bool is_inline = (ptr->value.data.x_ptr.special == ConstPtrSpecialInline);
+        if (casted_value->value.special != ConstValSpecialRuntime) {
+            ConstExprValue *dest_val = const_ptr_pointee(&ptr->value);
             if (dest_val->special != ConstValSpecialRuntime) {
-                *dest_val = casted_value->static_value;
+                *dest_val = casted_value->value;
                 return ir_analyze_void(ira, &store_ptr_instruction->base);
             }
         }
@@ -7448,11 +7489,11 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
         }
     }
 
-    if (ptr->static_value.special != ConstValSpecialRuntime) {
+    if (ptr->value.special != ConstValSpecialRuntime) {
         // This memory location is transforming from known at compile time to known at runtime.
         // We must emit our own var ptr instruction.
         // TODO can we delete this code now that we have inline var?
-        ptr->static_value.special = ConstValSpecialRuntime;
+        ptr->value.special = ConstValSpecialRuntime;
         IrInstruction *new_ptr_inst;
         if (ptr->id == IrInstructionIdVarPtr) {
             IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr;
@@ -7469,7 +7510,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
         } else {
             zig_unreachable();
         }
-        new_ptr_inst->type_entry = ptr->type_entry;
+        new_ptr_inst->value.type = ptr->value.type;
         ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.scope,
             store_ptr_instruction->base.source_node, new_ptr_inst, casted_value);
         return ir_analyze_void(ira, &store_ptr_instruction->base);
@@ -7481,7 +7522,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
 
 static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
     IrInstruction *expr_value = typeof_instruction->value->other;
-    TypeTableEntry *type_entry = expr_value->type_entry;
+    TypeTableEntry *type_entry = expr_value->value.type;
     switch (type_entry->id) {
         case TypeTableEntryIdInvalid:
             return type_entry;
@@ -7547,7 +7588,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
     }
 
     ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base,
-            type_value->static_value.depends_on_compile_var);
+            type_value->value.depends_on_compile_var);
     out_val->data.x_type = ptr_type;
     return ira->codegen->builtin_types.entry_type;
 }
@@ -7568,7 +7609,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
     }
 
     ConstExprValue *out_val = ir_build_const_from(ira, &ptr_type_child_instruction->base,
-            type_value->static_value.depends_on_compile_var);
+            type_value->value.depends_on_compile_var);
     out_val->data.x_type = type_entry->data.pointer.child_type;
     return ira->codegen->builtin_types.entry_type;
 }
@@ -7631,7 +7672,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
         IrInstructionSetDebugSafety *set_debug_safety_instruction)
 {
     IrInstruction *target_instruction = set_debug_safety_instruction->scope_value->other;
-    TypeTableEntry *target_type = target_instruction->type_entry;
+    TypeTableEntry *target_type = target_instruction->value.type;
     if (target_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
     ConstExprValue *target_val = ir_resolve_const(ira, target_instruction, UndefBad);
@@ -7694,7 +7735,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
         IrInstructionSliceType *slice_type_instruction)
 {
     IrInstruction *child_type = slice_type_instruction->child_type->other;
-    if (child_type->type_entry->id == TypeTableEntryIdInvalid)
+    if (child_type->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
     bool is_const = slice_type_instruction->is_const;
 
@@ -7736,7 +7777,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
             {
                 TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const);
                 ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base,
-                        child_type->static_value.depends_on_compile_var);
+                        child_type->value.depends_on_compile_var);
                 out_val->data.x_type = result_type;
                 return ira->codegen->builtin_types.entry_type;
             }
@@ -7770,7 +7811,7 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA
 
     for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
         input_list[i] = asm_instruction->input_list[i]->other;
-        if (input_list[i]->type_entry->id == TypeTableEntryIdInvalid)
+        if (input_list[i]->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
     }
 
@@ -7825,8 +7866,8 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
         case TypeTableEntryIdEnumTag:
             {
                 TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
-                bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var ||
-                    size_value->static_value.depends_on_compile_var;
+                bool depends_on_compile_var = child_type_value->value.depends_on_compile_var ||
+                    size_value->value.depends_on_compile_var;
                 ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base,
                         depends_on_compile_var);
                 out_val->data.x_type = result_type;
@@ -7927,10 +7968,10 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
 
 static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    TypeTableEntry *type_entry = value->type_entry;
+    TypeTableEntry *type_entry = value->value.type;
 
     if (type_entry->id == TypeTableEntryIdMaybe) {
         if (instr_is_comptime(value)) {
@@ -7961,11 +8002,11 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
         IrInstructionUnwrapMaybe *unwrap_maybe_instruction)
 {
     IrInstruction *value = unwrap_maybe_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     // This will be a pointer type because test null IR instruction operates on a pointer to a thing.
-    TypeTableEntry *ptr_type = value->type_entry;
+    TypeTableEntry *ptr_type = value->value.type;
     assert(ptr_type->id == TypeTableEntryIdPointer);
 
     TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
@@ -8008,59 +8049,59 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
 
 static TypeTableEntry *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) {
     IrInstruction *value = ctz_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid) {
+    if (value->value.type->id == TypeTableEntryIdInvalid) {
         return ira->codegen->builtin_types.entry_invalid;
-    } else if (value->type_entry->id == TypeTableEntryIdInt) {
-        if (value->static_value.special != ConstValSpecialRuntime) {
-            uint32_t result = bignum_ctz(&value->static_value.data.x_bignum,
-                    value->type_entry->data.integral.bit_count);
-            bool depends_on_compile_var = value->static_value.depends_on_compile_var;
+    } else if (value->value.type->id == TypeTableEntryIdInt) {
+        if (value->value.special != ConstValSpecialRuntime) {
+            uint32_t result = bignum_ctz(&value->value.data.x_bignum,
+                    value->value.type->data.integral.bit_count);
+            bool depends_on_compile_var = value->value.depends_on_compile_var;
             ConstExprValue *out_val = ir_build_const_from(ira, &ctz_instruction->base,
                     depends_on_compile_var);
             bignum_init_unsigned(&out_val->data.x_bignum, result);
-            return value->type_entry;
+            return value->value.type;
         }
 
         ir_build_ctz_from(&ira->new_irb, &ctz_instruction->base, value);
-        return value->type_entry;
+        return value->value.type;
     } else {
         ir_add_error_node(ira, ctz_instruction->base.source_node,
-            buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->type_entry->name)));
+            buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 }
 
 static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionClz *clz_instruction) {
     IrInstruction *value = clz_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid) {
+    if (value->value.type->id == TypeTableEntryIdInvalid) {
         return ira->codegen->builtin_types.entry_invalid;
-    } else if (value->type_entry->id == TypeTableEntryIdInt) {
-        if (value->static_value.special != ConstValSpecialRuntime) {
-            uint32_t result = bignum_clz(&value->static_value.data.x_bignum,
-                    value->type_entry->data.integral.bit_count);
-            bool depends_on_compile_var = value->static_value.depends_on_compile_var;
+    } else if (value->value.type->id == TypeTableEntryIdInt) {
+        if (value->value.special != ConstValSpecialRuntime) {
+            uint32_t result = bignum_clz(&value->value.data.x_bignum,
+                    value->value.type->data.integral.bit_count);
+            bool depends_on_compile_var = value->value.depends_on_compile_var;
             ConstExprValue *out_val = ir_build_const_from(ira, &clz_instruction->base,
                     depends_on_compile_var);
             bignum_init_unsigned(&out_val->data.x_bignum, result);
-            return value->type_entry;
+            return value->value.type;
         }
 
         ir_build_clz_from(&ira->new_irb, &clz_instruction->base, value);
-        return value->type_entry;
+        return value->value.type;
     } else {
         ir_add_error_node(ira, clz_instruction->base.source_node,
-            buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->type_entry->name)));
+            buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 }
 
 static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->invalid_instruction;
 
-    if (value->type_entry->id != TypeTableEntryIdEnum) {
+    if (value->value.type->id != TypeTableEntryIdEnum) {
         ir_add_error(ira, source_instr,
-            buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->type_entry->name)));
+            buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->value.type->name)));
         return ira->codegen->invalid_instruction;
     }
 
@@ -8071,10 +8112,10 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
                 source_instr->scope, source_instr->source_node);
-        const_instruction->base.type_entry = value->type_entry->data.enumeration.tag_type;
-        const_instruction->base.static_value.special = ConstValSpecialStatic;
-        const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
-        bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, val->data.x_enum.tag);
+        const_instruction->base.value.type = value->value.type->data.enumeration.tag_type;
+        const_instruction->base.value.special = ConstValSpecialStatic;
+        const_instruction->base.value.depends_on_compile_var = val->depends_on_compile_var;
+        bignum_init_unsigned(&const_instruction->base.value.data.x_bignum, val->data.x_enum.tag);
         return &const_instruction->base;
     }
 
@@ -8085,7 +8126,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
         IrInstructionSwitchBr *switch_br_instruction)
 {
     IrInstruction *target_value = switch_br_instruction->target_value->other;
-    if (target_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (target_value->value.type->id == TypeTableEntryIdInvalid)
         return ir_unreach_error(ira);
 
     size_t case_count = switch_br_instruction->case_count;
@@ -8103,24 +8144,24 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
         for (size_t i = 0; i < case_count; i += 1) {
             IrInstructionSwitchBrCase *old_case = &switch_br_instruction->cases[i];
             IrInstruction *case_value = old_case->value->other;
-            if (case_value->type_entry->id == TypeTableEntryIdInvalid)
+            if (case_value->value.type->id == TypeTableEntryIdInvalid)
                 return ir_unreach_error(ira);
 
-            if (case_value->type_entry->id == TypeTableEntryIdEnum) {
+            if (case_value->value.type->id == TypeTableEntryIdEnum) {
                 case_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, case_value);
-                if (case_value->type_entry->id == TypeTableEntryIdInvalid)
+                if (case_value->value.type->id == TypeTableEntryIdInvalid)
                     return ir_unreach_error(ira);
             }
 
-            IrInstruction *casted_case_value = ir_implicit_cast(ira, case_value, target_value->type_entry);
-            if (casted_case_value->type_entry->id == TypeTableEntryIdInvalid)
+            IrInstruction *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value.type);
+            if (casted_case_value->value.type->id == TypeTableEntryIdInvalid)
                 return ir_unreach_error(ira);
 
             ConstExprValue *case_val = ir_resolve_const(ira, casted_case_value, UndefBad);
             if (!case_val)
                 return ir_unreach_error(ira);
 
-            if (const_values_equal(target_val, case_val, target_value->type_entry)) {
+            if (const_values_equal(target_val, case_val)) {
                 old_dest_block = old_case->block;
                 break;
             }
@@ -8144,17 +8185,17 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
 
         IrInstruction *old_value = old_case->value;
         IrInstruction *new_value = old_value->other;
-        if (new_value->type_entry->id == TypeTableEntryIdInvalid)
+        if (new_value->value.type->id == TypeTableEntryIdInvalid)
             continue;
 
-        if (new_value->type_entry->id == TypeTableEntryIdEnum) {
+        if (new_value->value.type->id == TypeTableEntryIdEnum) {
             new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value);
-            if (new_value->type_entry->id == TypeTableEntryIdInvalid)
+            if (new_value->value.type->id == TypeTableEntryIdInvalid)
                 continue;
         }
 
-        IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->type_entry);
-        if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
+        IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value.type);
+        if (casted_new_value->value.type->id == TypeTableEntryIdInvalid)
             continue;
 
         if (!ir_resolve_const(ira, casted_new_value, UndefBad))
@@ -8173,15 +8214,15 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
         IrInstructionSwitchTarget *switch_target_instruction)
 {
     IrInstruction *target_value_ptr = switch_target_instruction->target_value_ptr->other;
-    if (target_value_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (target_value_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    assert(target_value_ptr->type_entry->id == TypeTableEntryIdPointer);
-    TypeTableEntry *target_type = target_value_ptr->type_entry->data.pointer.child_type;
-    bool depends_on_compile_var = target_value_ptr->static_value.depends_on_compile_var;
+    assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
+    TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
+    bool depends_on_compile_var = target_value_ptr->value.depends_on_compile_var;
     ConstExprValue *pointee_val = nullptr;
-    if (target_value_ptr->static_value.special != ConstValSpecialRuntime) {
-        pointee_val = const_ptr_pointee(&target_value_ptr->static_value);
+    if (target_value_ptr->value.special != ConstValSpecialRuntime) {
+        pointee_val = const_ptr_pointee(&target_value_ptr->value);
         if (pointee_val->special == ConstValSpecialRuntime)
             pointee_val = nullptr;
     }
@@ -8206,6 +8247,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
                 ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base,
                         depends_on_compile_var);
                 *out_val = *pointee_val;
+                out_val->type = target_type;
                 return target_type;
             }
 
@@ -8223,7 +8265,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
 
                 IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
                     switch_target_instruction->base.source_node, target_value_ptr);
-                enum_value->type_entry = target_type;
+                enum_value->value.type = target_type;
                 ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value);
                 return tag_type;
             }
@@ -8251,24 +8293,24 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
 
 static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstructionSwitchVar *instruction) {
     IrInstruction *target_value_ptr = instruction->target_value_ptr->other;
-    if (target_value_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (target_value_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *prong_value = instruction->prong_value->other;
-    if (prong_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (prong_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    assert(target_value_ptr->type_entry->id == TypeTableEntryIdPointer);
-    TypeTableEntry *target_type = target_value_ptr->type_entry->data.pointer.child_type;
+    assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
+    TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
     if (target_type->id == TypeTableEntryIdEnum) {
         ConstExprValue *prong_val = ir_resolve_const(ira, prong_value, UndefBad);
         if (!prong_val)
             return ira->codegen->builtin_types.entry_invalid;
 
         TypeEnumField *field = &target_type->data.enumeration.fields[prong_val->data.x_bignum.data.x_uint];
-        if (prong_value->type_entry->id == TypeTableEntryIdEnumTag) {
+        if (prong_value->value.type->id == TypeTableEntryIdEnumTag) {
             field = &target_type->data.enumeration.fields[prong_val->data.x_bignum.data.x_uint];
-        } else if (prong_value->type_entry->id == TypeTableEntryIdEnum) {
+        } else if (prong_value->value.type->id == TypeTableEntryIdEnum) {
             field = &target_type->data.enumeration.fields[prong_val->data.x_enum.tag];
         } else {
             zig_unreachable();
@@ -8280,7 +8322,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
 
         ir_build_enum_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
         return get_pointer_to_type(ira->codegen, field->type_entry,
-                target_value_ptr->type_entry->data.pointer.is_const);
+                target_value_ptr->value.type->data.pointer.is_const);
     } else {
         ErrorMsg *msg = ir_add_error(ira, &instruction->base,
             buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name)));
@@ -8293,14 +8335,14 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstruc
     IrInstruction *value = enum_tag_instruction->value->other;
     IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value);
     ir_link_new_instruction(new_instruction, &enum_tag_instruction->base);
-    return new_instruction->type_entry;
+    return new_instruction->value.type;
 }
 
 static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,
         IrInstructionStaticEval *static_eval_instruction)
 {
     IrInstruction *value = static_eval_instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
@@ -8309,7 +8351,7 @@ static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,
 
     ConstExprValue *out_val = ir_build_const_from(ira, &static_eval_instruction->base, val->depends_on_compile_var);
     *out_val = *val;
-    return value->type_entry;
+    return value->value.type;
 }
 
 static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructionImport *import_instruction) {
@@ -8317,7 +8359,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
     Buf *import_target_str = ir_resolve_str(ira, name_value);
     if (!import_target_str)
         return ira->codegen->builtin_types.entry_invalid;
-    bool depends_on_compile_var = name_value->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = name_value->value.depends_on_compile_var;
 
     AstNode *source_node = import_instruction->base.source_node;
     ImportTableEntry *import = source_node->owner;
@@ -8390,16 +8432,16 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira,
         IrInstructionArrayLen *array_len_instruction)
 {
     IrInstruction *array_value = array_len_instruction->array_value->other;
-    TypeTableEntry *canon_type = get_underlying_type(array_value->type_entry);
+    TypeTableEntry *canon_type = get_underlying_type(array_value->value.type);
     if (canon_type->id == TypeTableEntryIdInvalid) {
         return ira->codegen->builtin_types.entry_invalid;
     } else if (canon_type->id == TypeTableEntryIdArray) {
-        bool depends_on_compile_var = array_value->static_value.depends_on_compile_var;
+        bool depends_on_compile_var = array_value->value.depends_on_compile_var;
         return ir_analyze_const_usize(ira, &array_len_instruction->base,
                 canon_type->data.array.len, depends_on_compile_var);
     } else if (is_slice(canon_type)) {
-        if (array_value->static_value.special != ConstValSpecialRuntime) {
-            ConstExprValue *len_val = &array_value->static_value.data.x_struct.fields[slice_len_index];
+        if (array_value->value.special != ConstValSpecialRuntime) {
+            ConstExprValue *len_val = &array_value->value.data.x_struct.fields[slice_len_index];
             if (len_val->special != ConstValSpecialRuntime) {
                 bool depends_on_compile_var = len_val->depends_on_compile_var;
                 return ir_analyze_const_usize(ira, &array_len_instruction->base,
@@ -8409,12 +8451,12 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira,
         TypeStructField *field = &canon_type->data.structure.fields[slice_len_index];
         IrInstruction *len_ptr = ir_build_struct_field_ptr(&ira->new_irb, array_len_instruction->base.scope,
                 array_len_instruction->base.source_node, array_value, field);
-        len_ptr->type_entry = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true);
+        len_ptr->value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_usize, true);
         ir_build_load_ptr_from(&ira->new_irb, &array_len_instruction->base, len_ptr);
         return ira->codegen->builtin_types.entry_usize;
     } else {
         ir_add_error_node(ira, array_len_instruction->base.source_node,
-            buf_sprintf("type '%s' has no field 'len'", buf_ptr(&array_value->type_entry->name)));
+            buf_sprintf("type '%s' has no field 'len'", buf_ptr(&array_value->value.type->name)));
         // TODO if this is a typedecl, add error note showing the declaration of the type decl
         return ira->codegen->builtin_types.entry_invalid;
     }
@@ -8444,13 +8486,14 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
 
     ConstExprValue const_val = {};
     const_val.special = ConstValSpecialStatic;
+    const_val.type = container_type;
     const_val.depends_on_compile_var = depends_on_compile_var;
     const_val.data.x_struct.fields = allocate<ConstExprValue>(actual_field_count);
     for (size_t i = 0; i < instr_field_count; i += 1) {
         IrInstructionContainerInitFieldsField *field = &fields[i];
 
         IrInstruction *field_value = field->value->other;
-        if (field_value->type_entry->id == TypeTableEntryIdInvalid)
+        if (field_value->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
         TypeStructField *type_field = find_struct_type_field(container_type, field->name);
@@ -8481,7 +8524,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
         new_fields[field_index].type_struct_field = type_field;
 
         if (const_val.special == ConstValSpecialStatic) {
-            if (is_comptime || casted_field_value->static_value.special != ConstValSpecialRuntime) {
+            if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
                 ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
                 if (!field_val)
                     return ira->codegen->builtin_types.entry_invalid;
@@ -8529,16 +8572,16 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
         IrInstructionContainerInitList *instruction)
 {
     IrInstruction *container_type_value = instruction->container_type->other;
-    if (container_type_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (container_type_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     size_t elem_count = instruction->item_count;
-    if (container_type_value->type_entry->id == TypeTableEntryIdMetaType) {
+    if (container_type_value->value.type->id == TypeTableEntryIdMetaType) {
         TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
         if (container_type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
-        bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
+        bool depends_on_compile_var = container_type_value->value.depends_on_compile_var;
 
         if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {
             return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
@@ -8547,9 +8590,11 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
             TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
             assert(pointer_type->id == TypeTableEntryIdPointer);
             TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
+            TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
 
             ConstExprValue const_val = {};
             const_val.special = ConstValSpecialStatic;
+            const_val.type = fixed_size_array_type;
             const_val.depends_on_compile_var = depends_on_compile_var;
             const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
             const_val.data.x_array.size = elem_count;
@@ -8562,7 +8607,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
 
             for (size_t i = 0; i < elem_count; i += 1) {
                 IrInstruction *arg_value = instruction->items[i]->other;
-                if (arg_value->type_entry->id == TypeTableEntryIdInvalid)
+                if (arg_value->value.type->id == TypeTableEntryIdInvalid)
                     return ira->codegen->builtin_types.entry_invalid;
 
                 IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
@@ -8572,7 +8617,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
                 new_items[i] = casted_arg;
 
                 if (const_val.special == ConstValSpecialStatic) {
-                    if (is_comptime || casted_arg->static_value.special != ConstValSpecialRuntime) {
+                    if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
                         ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
                         if (!elem_val)
                             return ira->codegen->builtin_types.entry_invalid;
@@ -8586,7 +8631,6 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
                 }
             }
 
-            TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
             if (const_val.special == ConstValSpecialStatic) {
                 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var);
                 *out_val = const_val;
@@ -8619,7 +8663,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
                     buf_ptr(&container_type->name)));
             return ira->codegen->builtin_types.entry_invalid;
         }
-    } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) {
+    } else if (container_type_value->value.type->id == TypeTableEntryIdEnumTag) {
         if (elem_count != 1) {
             ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element"));
             return ira->codegen->builtin_types.entry_invalid;
@@ -8628,7 +8672,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
         if (!tag_value)
             return ira->codegen->builtin_types.entry_invalid;
 
-        TypeTableEntry *enum_type = container_type_value->type_entry->data.enum_tag.enum_type;
+        TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type;
 
         uint64_t tag_uint = tag_value->data.x_bignum.data.x_uint;
         TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint];
@@ -8645,7 +8689,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
             if (!init_val)
                 return ira->codegen->builtin_types.entry_invalid;
             ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
-                    casted_init_value->static_value.depends_on_compile_var);
+                    casted_init_value->value.depends_on_compile_var);
             out_val->data.x_enum.tag = tag_uint;
             out_val->data.x_enum.payload = init_val;
             return enum_type;
@@ -8657,7 +8701,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
         return enum_type;
     } else {
         ir_add_error(ira, container_type_value,
-            buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->type_entry->name)));
+            buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 }
@@ -8668,7 +8712,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *i
     if (container_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = container_type_value->value.depends_on_compile_var;
 
     return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
         instruction->field_count, instruction->fields, depends_on_compile_var);
@@ -8678,7 +8722,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
         IrInstruction *target_type_value, bool is_max)
 {
     TypeTableEntry *target_type = ir_resolve_type(ira, target_type_value);
-    bool depends_on_compile_var = target_type_value->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = target_type_value->value.depends_on_compile_var;
     TypeTableEntry *canon_type = get_underlying_type(target_type);
     switch (canon_type->id) {
         case TypeTableEntryIdInvalid:
@@ -8763,35 +8807,22 @@ static TypeTableEntry *ir_analyze_instruction_compile_err(IrAnalyze *ira,
 
 static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstructionErrName *instruction) {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    IrInstruction *casted_value = ir_implicit_cast(ira, value, value->type_entry);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type);
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
-    if (casted_value->static_value.special == ConstValSpecialStatic) {
-        ErrorTableEntry *err = casted_value->static_value.data.x_pure_err;
+    if (casted_value->value.special == ConstValSpecialStatic) {
+        ErrorTableEntry *err = casted_value->value.data.x_pure_err;
         if (!err->cached_error_name_val) {
-            err->cached_error_name_val = allocate<ConstExprValue>(1);
-            err->cached_error_name_val->special = ConstValSpecialStatic;
-            err->cached_error_name_val->data.x_struct.fields = allocate<ConstExprValue>(2);
-
-            ConstExprValue *array_val = allocate<ConstExprValue>(1);
-            init_const_str_lit(array_val, &err->name);
-
-            ConstExprValue *ptr_val = &err->cached_error_name_val->data.x_struct.fields[slice_ptr_index];
-            ptr_val->special = ConstValSpecialStatic;
-            ptr_val->data.x_ptr.base_ptr = array_val;
-            ptr_val->data.x_ptr.index = 0;
-
-            ConstExprValue *len_val = &err->cached_error_name_val->data.x_struct.fields[slice_len_index];
-            len_val->special = ConstValSpecialStatic;
-            bignum_init_unsigned(&len_val->data.x_bignum, buf_len(&err->name));
+            ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);
+            err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);
         }
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
-            casted_value->static_value.depends_on_compile_var);
+            casted_value->value.depends_on_compile_var);
         *out_val = *err->cached_error_name_val;
         return str_type;
     }
@@ -8813,7 +8844,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc
     IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
         ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
         &cimport_scope->buf, block_node, nullptr, nullptr);
-    if (result->type_entry->id == TypeTableEntryIdInvalid)
+    if (result->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     find_libc_include_path(ira->codegen);
@@ -8855,7 +8886,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc
 
 static TypeTableEntry *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) {
     IrInstruction *name_value = instruction->name->other;
-    if (name_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (name_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     Buf *include_name = ir_resolve_str(ira, name_value);
@@ -8874,7 +8905,7 @@ static TypeTableEntry *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstru
 
 static TypeTableEntry *ir_analyze_instruction_c_define(IrAnalyze *ira, IrInstructionCDefine *instruction) {
     IrInstruction *name = instruction->name->other;
-    if (name->type_entry->id == TypeTableEntryIdInvalid)
+    if (name->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     Buf *define_name = ir_resolve_str(ira, name);
@@ -8882,7 +8913,7 @@ static TypeTableEntry *ir_analyze_instruction_c_define(IrAnalyze *ira, IrInstruc
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     Buf *define_value = ir_resolve_str(ira, value);
@@ -8901,7 +8932,7 @@ static TypeTableEntry *ir_analyze_instruction_c_define(IrAnalyze *ira, IrInstruc
 
 static TypeTableEntry *ir_analyze_instruction_c_undef(IrAnalyze *ira, IrInstructionCUndef *instruction) {
     IrInstruction *name = instruction->name->other;
-    if (name->type_entry->id == TypeTableEntryIdInvalid)
+    if (name->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     Buf *undef_name = ir_resolve_str(ira, name);
@@ -8920,7 +8951,7 @@ static TypeTableEntry *ir_analyze_instruction_c_undef(IrAnalyze *ira, IrInstruct
 
 static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstructionEmbedFile *instruction) {
     IrInstruction *name = instruction->name->other;
-    if (name->type_entry->id == TypeTableEntryIdInvalid)
+    if (name->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     Buf *rel_file_path = ir_resolve_str(ira, name);
@@ -8953,26 +8984,26 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
 
     bool depends_on_compile_var = true;
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
-    init_const_str_lit(out_val, &file_contents);
+    init_const_str_lit(ira->codegen, out_val, &file_contents);
 
     return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents));
 }
 
 static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
     IrInstruction *ptr = instruction->ptr->other;
-    if (ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *cmp_value = instruction->cmp_value->other;
-    if (cmp_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (cmp_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *new_value = instruction->new_value->other;
-    if (new_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (new_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *success_order_value = instruction->success_order_value->other;
-    if (success_order_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (success_order_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     AtomicOrder success_order;
@@ -8980,27 +9011,27 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *failure_order_value = instruction->failure_order_value->other;
-    if (failure_order_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (failure_order_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     AtomicOrder failure_order;
     if (!ir_resolve_atomic_order(ira, failure_order_value, &failure_order))
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (ptr->type_entry->id != TypeTableEntryIdPointer) {
+    if (ptr->value.type->id != TypeTableEntryIdPointer) {
         ir_add_error(ira, instruction->ptr,
-            buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->type_entry->name)));
+            buf_sprintf("expected pointer argument, found '%s'", buf_ptr(&ptr->value.type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type;
+    TypeTableEntry *child_type = ptr->value.type->data.pointer.child_type;
 
     IrInstruction *casted_cmp_value = ir_implicit_cast(ira, cmp_value, child_type);
-    if (casted_cmp_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_cmp_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, child_type);
-    if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_new_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     if (success_order < AtomicOrderMonotonic) {
@@ -9031,7 +9062,7 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
 
 static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) {
     IrInstruction *order_value = instruction->order_value->other;
-    if (order_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (order_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     AtomicOrder order;
@@ -9044,11 +9075,11 @@ static TypeTableEntry *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructio
 
 static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstructionDivExact *instruction) {
     IrInstruction *op1 = instruction->op1->other;
-    if (op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *op2 = instruction->op2->other;
-    if (op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
 
@@ -9070,15 +9101,15 @@ static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstru
     }
 
     IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, result_type);
-    if (casted_op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, result_type);
-    if (casted_op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (casted_op1->static_value.special == ConstValSpecialStatic &&
-        casted_op2->static_value.special == ConstValSpecialStatic)
+    if (casted_op1->value.special == ConstValSpecialStatic &&
+        casted_op2->value.special == ConstValSpecialStatic)
     {
         ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
         ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
@@ -9101,8 +9132,8 @@ static TypeTableEntry *ir_analyze_instruction_div_exact(IrAnalyze *ira, IrInstru
             return ira->codegen->builtin_types.entry_invalid;
         }
 
-        bool depends_on_compile_var = casted_op1->static_value.depends_on_compile_var ||
-            casted_op2->static_value.depends_on_compile_var;
+        bool depends_on_compile_var = casted_op1->value.depends_on_compile_var ||
+            casted_op2->value.depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
         bignum_div(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
         return result_type;
@@ -9129,7 +9160,7 @@ static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruc
     }
 
     IrInstruction *target = instruction->target->other;
-    TypeTableEntry *src_type = target->type_entry;
+    TypeTableEntry *src_type = target->value.type;
     TypeTableEntry *canon_src_type = get_underlying_type(src_type);
     if (canon_src_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
@@ -9154,10 +9185,10 @@ static TypeTableEntry *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruc
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    if (target->static_value.special == ConstValSpecialStatic) {
-        bool depends_on_compile_var = dest_type_value->static_value.depends_on_compile_var || target->static_value.depends_on_compile_var;
+    if (target->value.special == ConstValSpecialStatic) {
+        bool depends_on_compile_var = dest_type_value->value.depends_on_compile_var || target->value.depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
-        bignum_init_bignum(&out_val->data.x_bignum, &target->static_value.data.x_bignum);
+        bignum_init_bignum(&out_val->data.x_bignum, &target->value.data.x_bignum);
         bignum_truncate(&out_val->data.x_bignum, canon_dest_type->data.integral.bit_count);
         return dest_type;
     }
@@ -9177,8 +9208,8 @@ static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruc
     if (!ir_resolve_usize(ira, bit_count_value, &bit_count))
         return ira->codegen->builtin_types.entry_invalid;
 
-    bool depends_on_compile_var = is_signed_value->static_value.depends_on_compile_var ||
-        bit_count_value->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = is_signed_value->value.depends_on_compile_var ||
+        bit_count_value->value.depends_on_compile_var;
 
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
     out_val->data.x_type = get_int_type(ira->codegen, is_signed, bit_count);
@@ -9187,19 +9218,19 @@ static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruc
 
 static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
 
     IrInstruction *casted_value = ir_implicit_cast(ira, value, bool_type);
-    if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (casted_value->static_value.special != ConstValSpecialRuntime) {
-        bool depends_on_compile_var = casted_value->static_value.depends_on_compile_var;
+    if (casted_value->value.special != ConstValSpecialRuntime) {
+        bool depends_on_compile_var = casted_value->value.depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
-        out_val->data.x_bool = !casted_value->static_value.data.x_bool;
+        out_val->data.x_bool = !casted_value->value.data.x_bool;
         return bool_type;
     }
 
@@ -9209,11 +9240,11 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
 
 static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
     IrInstruction *type_value = instruction->type_value->other;
-    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (type_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *count_value = instruction->count->other;
-    if (count_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (count_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *child_type = ir_resolve_type(ira, type_value);
@@ -9234,15 +9265,15 @@ static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructi
 
 static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
     IrInstruction *dest_ptr = instruction->dest_ptr->other;
-    if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (dest_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *byte_value = instruction->byte->other;
-    if (byte_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (byte_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *count_value = instruction->count->other;
-    if (count_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (count_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
@@ -9250,22 +9281,22 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
     TypeTableEntry *u8_ptr = get_pointer_to_type(ira->codegen, u8, false);
 
     IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
-    if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_dest_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_byte = ir_implicit_cast(ira, byte_value, u8);
-    if (casted_byte->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_byte->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize);
-    if (casted_count->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_count->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (casted_dest_ptr->static_value.special == ConstValSpecialStatic &&
-        casted_byte->static_value.special == ConstValSpecialStatic &&
-        casted_count->static_value.special == ConstValSpecialStatic)
+    if (casted_dest_ptr->value.special == ConstValSpecialStatic &&
+        casted_byte->value.special == ConstValSpecialStatic &&
+        casted_count->value.special == ConstValSpecialStatic)
     {
-        ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value;
+        ConstExprValue *dest_ptr_val = &casted_dest_ptr->value;
 
         ConstExprValue *dest_elements;
         size_t start;
@@ -9281,14 +9312,14 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
             bound_end = array_val->data.x_array.size;
         }
 
-        size_t count = casted_count->static_value.data.x_bignum.data.x_uint;
+        size_t count = casted_count->value.data.x_bignum.data.x_uint;
         size_t end = start + count;
         if (end > bound_end) {
             ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access"));
             return ira->codegen->builtin_types.entry_invalid;
         }
 
-        ConstExprValue *byte_val = &casted_byte->static_value;
+        ConstExprValue *byte_val = &casted_byte->value;
         for (size_t i = start; i < end; i += 1) {
             dest_elements[i] = *byte_val;
         }
@@ -9303,15 +9334,15 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
 
 static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructionMemcpy *instruction) {
     IrInstruction *dest_ptr = instruction->dest_ptr->other;
-    if (dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (dest_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *src_ptr = instruction->src_ptr->other;
-    if (src_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (src_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *count_value = instruction->count->other;
-    if (count_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (count_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
@@ -9320,24 +9351,24 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
     TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true);
 
     IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
-    if (casted_dest_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_dest_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_src_ptr = ir_implicit_cast(ira, src_ptr, u8_ptr_const);
-    if (casted_src_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_src_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_count = ir_implicit_cast(ira, count_value, usize);
-    if (casted_count->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_count->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (casted_dest_ptr->static_value.special == ConstValSpecialStatic &&
-        casted_src_ptr->static_value.special == ConstValSpecialStatic &&
-        casted_count->static_value.special == ConstValSpecialStatic)
+    if (casted_dest_ptr->value.special == ConstValSpecialStatic &&
+        casted_src_ptr->value.special == ConstValSpecialStatic &&
+        casted_count->value.special == ConstValSpecialStatic)
     {
-        size_t count = casted_count->static_value.data.x_bignum.data.x_uint;
+        size_t count = casted_count->value.data.x_bignum.data.x_uint;
 
-        ConstExprValue *dest_ptr_val = &casted_dest_ptr->static_value;
+        ConstExprValue *dest_ptr_val = &casted_dest_ptr->value;
         ConstExprValue *dest_elements;
         size_t dest_start;
         size_t dest_end;
@@ -9357,7 +9388,7 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
             return ira->codegen->builtin_types.entry_invalid;
         }
 
-        ConstExprValue *src_ptr_val = &casted_src_ptr->static_value;
+        ConstExprValue *src_ptr_val = &casted_src_ptr->value;
         ConstExprValue *src_elements;
         size_t src_start;
         size_t src_end;
@@ -9393,31 +9424,31 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
 
 static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) {
     IrInstruction *ptr = instruction->ptr->other;
-    if (ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *start = instruction->start->other;
-    if (start->type_entry->id == TypeTableEntryIdInvalid)
+    if (start->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
     IrInstruction *casted_start = ir_implicit_cast(ira, start, usize);
-    if (casted_start->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_start->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *end;
     if (instruction->end) {
         end = instruction->end->other;
-        if (end->type_entry->id == TypeTableEntryIdInvalid)
+        if (end->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
         end = ir_implicit_cast(ira, end, usize);
-        if (end->type_entry->id == TypeTableEntryIdInvalid)
+        if (end->value.type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
     } else {
         end = nullptr;
     }
 
-    TypeTableEntry *array_type = get_underlying_type(ptr->type_entry);
+    TypeTableEntry *array_type = get_underlying_type(ptr->value.type);
 
     TypeTableEntry *return_type;
 
@@ -9435,38 +9466,38 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
                 instruction->is_const);
     } else {
         ir_add_error(ira, &instruction->base,
-            buf_sprintf("slice of non-array type '%s'", buf_ptr(&ptr->type_entry->name)));
+            buf_sprintf("slice of non-array type '%s'", buf_ptr(&ptr->value.type->name)));
         // TODO if this is a typedecl, add error note showing the declaration of the type decl
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    if (ptr->static_value.special == ConstValSpecialStatic &&
-        casted_start->static_value.special == ConstValSpecialStatic &&
-        (!end || end->static_value.special == ConstValSpecialStatic))
+    if (ptr->value.special == ConstValSpecialStatic &&
+        casted_start->value.special == ConstValSpecialStatic &&
+        (!end || end->value.special == ConstValSpecialStatic))
     {
         bool depends_on_compile_var =
-            ptr->static_value.depends_on_compile_var ||
-            casted_start->static_value.depends_on_compile_var ||
-            (end ? end->static_value.depends_on_compile_var : false);
+            ptr->value.depends_on_compile_var ||
+            casted_start->value.depends_on_compile_var ||
+            (end ? end->value.depends_on_compile_var : false);
 
         ConstExprValue *base_ptr;
         size_t abs_offset;
         size_t rel_end;
         if (array_type->id == TypeTableEntryIdArray) {
-            base_ptr = &ptr->static_value;
+            base_ptr = &ptr->value;
             abs_offset = 0;
             rel_end = array_type->data.array.len;
         } else if (array_type->id == TypeTableEntryIdPointer) {
-            base_ptr = ptr->static_value.data.x_ptr.base_ptr;
-            abs_offset = ptr->static_value.data.x_ptr.index;
+            base_ptr = ptr->value.data.x_ptr.base_ptr;
+            abs_offset = ptr->value.data.x_ptr.index;
             if (abs_offset == SIZE_MAX) {
                 rel_end = 1;
             } else {
                 rel_end = base_ptr->data.x_array.size - abs_offset;
             }
         } else if (is_slice(array_type)) {
-            ConstExprValue *ptr_val = &ptr->static_value.data.x_struct.fields[slice_ptr_index];
-            ConstExprValue *len_val = &ptr->static_value.data.x_struct.fields[slice_len_index];
+            ConstExprValue *ptr_val = &ptr->value.data.x_struct.fields[slice_ptr_index];
+            ConstExprValue *len_val = &ptr->value.data.x_struct.fields[slice_len_index];
             base_ptr = ptr_val->data.x_ptr.base_ptr;
             abs_offset = ptr_val->data.x_ptr.index;
 
@@ -9479,7 +9510,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
             zig_unreachable();
         }
 
-        uint64_t start_scalar = casted_start->static_value.data.x_bignum.data.x_uint;
+        uint64_t start_scalar = casted_start->value.data.x_bignum.data.x_uint;
         if (start_scalar > rel_end) {
             ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
             return ira->codegen->builtin_types.entry_invalid;
@@ -9487,7 +9518,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
 
         uint64_t end_scalar;
         if (end) {
-            end_scalar = end->static_value.data.x_bignum.data.x_uint;
+            end_scalar = end->value.data.x_bignum.data.x_uint;
         } else {
             end_scalar = rel_end;
         }
@@ -9504,18 +9535,17 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
         out_val->data.x_struct.fields = allocate<ConstExprValue>(2);
 
         ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index];
-        ptr_val->special = ConstValSpecialStatic;
-        ptr_val->data.x_ptr.base_ptr = base_ptr;
-        ptr_val->data.x_ptr.index = (abs_offset != SIZE_MAX) ? (abs_offset + start_scalar) : SIZE_MAX;
+        size_t index = (abs_offset != SIZE_MAX) ? (abs_offset + start_scalar) : SIZE_MAX;
+        init_const_ptr(ira->codegen, ptr_val, base_ptr, index, instruction->is_const);
 
         ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
-        len_val->special = ConstValSpecialStatic;
-        bignum_init_unsigned(&len_val->data.x_bignum, rel_end);
+        init_const_usize(ira->codegen, len_val, rel_end);
 
         return return_type;
     }
 
-    IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr, casted_start, end, instruction->is_const);
+    IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr,
+            casted_start, end, instruction->is_const, instruction->safety_check_on);
     ir_add_alloca(ira, new_instruction, return_type);
 
     return return_type;
@@ -9523,7 +9553,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
 
 static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) {
     IrInstruction *container = instruction->container->other;
-    if (container->type_entry->id == TypeTableEntryIdInvalid)
+    if (container->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
     TypeTableEntry *container_type = ir_resolve_type(ira, container);
     TypeTableEntry *canon_type = get_underlying_type(container_type);
@@ -9542,7 +9572,7 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
         return ira->codegen->builtin_types.entry_invalid;
     }
 
-    bool depends_on_compile_var = container->static_value.depends_on_compile_var;
+    bool depends_on_compile_var = container->value.depends_on_compile_var;
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
     bignum_init_unsigned(&out_val->data.x_bignum, result);
     return ira->codegen->builtin_types.entry_num_lit_int;
@@ -9571,7 +9601,7 @@ static TypeTableEntry *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIn
 
 static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
     IrInstruction *type_value = instruction->type_value->other;
-    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (type_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
     TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
 
@@ -9583,7 +9613,7 @@ static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstruct
         return ira->codegen->builtin_types.entry_invalid;
     } else {
         uint64_t align_in_bytes = LLVMABISizeOfType(ira->codegen->target_data_ref, type_entry->type_ref);
-        bool depends_on_compile_var = type_value->static_value.depends_on_compile_var;
+        bool depends_on_compile_var = type_value->value.depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
         bignum_init_unsigned(&out_val->data.x_bignum, align_in_bytes);
         return ira->codegen->builtin_types.entry_num_lit_int;
@@ -9592,7 +9622,7 @@ static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstruct
 
 static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) {
     IrInstruction *type_value = instruction->type_value->other;
-    if (type_value->type_entry->id == TypeTableEntryIdInvalid)
+    if (type_value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
     TypeTableEntry *dest_type = ir_resolve_type(ira, type_value);
     TypeTableEntry *canon_type = get_underlying_type(dest_type);
@@ -9607,41 +9637,41 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
     }
 
     IrInstruction *op1 = instruction->op1->other;
-    if (op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, dest_type);
-    if (casted_op1->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_op1->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *op2 = instruction->op2->other;
-    if (op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type);
-    if (casted_op2->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_op2->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     IrInstruction *result_ptr = instruction->result_ptr->other;
-    if (result_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (result_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     TypeTableEntry *expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
     IrInstruction *casted_result_ptr = ir_implicit_cast(ira, result_ptr, expected_ptr_type);
-    if (casted_result_ptr->type_entry->id == TypeTableEntryIdInvalid)
+    if (casted_result_ptr->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    if (casted_op1->static_value.special == ConstValSpecialStatic &&
-        casted_op2->static_value.special == ConstValSpecialStatic &&
-        casted_result_ptr->static_value.special == ConstValSpecialStatic)
+    if (casted_op1->value.special == ConstValSpecialStatic &&
+        casted_op2->value.special == ConstValSpecialStatic &&
+        casted_result_ptr->value.special == ConstValSpecialStatic)
     {
-        bool depends_on_compile_var = type_value->static_value.depends_on_compile_var ||
-            casted_op1->static_value.depends_on_compile_var || casted_op2->static_value.depends_on_compile_var ||
-            casted_result_ptr->static_value.depends_on_compile_var;
+        bool depends_on_compile_var = type_value->value.depends_on_compile_var ||
+            casted_op1->value.depends_on_compile_var || casted_op2->value.depends_on_compile_var ||
+            casted_result_ptr->value.depends_on_compile_var;
         ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
-        BigNum *op1_bignum = &casted_op1->static_value.data.x_bignum;
-        BigNum *op2_bignum = &casted_op2->static_value.data.x_bignum;
-        ConstExprValue *pointee_val = const_ptr_pointee(&casted_result_ptr->static_value);
+        BigNum *op1_bignum = &casted_op1->value.data.x_bignum;
+        BigNum *op2_bignum = &casted_op2->value.data.x_bignum;
+        ConstExprValue *pointee_val = const_ptr_pointee(&casted_result_ptr->value);
         BigNum *dest_bignum = &pointee_val->data.x_bignum;
         switch (instruction->op) {
             case IrOverflowOpAdd:
@@ -9674,10 +9704,10 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
 
 static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
-    TypeTableEntry *non_canon_type = value->type_entry;
+    TypeTableEntry *non_canon_type = value->value.type;
 
     TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
     if (canon_type->id == TypeTableEntryIdInvalid) {
@@ -9713,9 +9743,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
     IrInstructionUnwrapErrCode *instruction)
 {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
-    TypeTableEntry *ptr_type = value->type_entry;
+    TypeTableEntry *ptr_type = value->value.type;
 
     // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
     assert(ptr_type->id == TypeTableEntryIdPointer);
@@ -9756,9 +9786,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
     IrInstructionUnwrapErrPayload *instruction)
 {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
-    TypeTableEntry *ptr_type = value->type_entry;
+    TypeTableEntry *ptr_type = value->value.type;
 
     // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
     assert(ptr_type->id == TypeTableEntryIdPointer);
@@ -9824,14 +9854,14 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
         if (param_info->type->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
 
-        depends_on_compile_var = depends_on_compile_var || param_type_value->static_value.depends_on_compile_var;
+        depends_on_compile_var = depends_on_compile_var || param_type_value->value.depends_on_compile_var;
     }
 
     IrInstruction *return_type_value = instruction->return_type->other;
     fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
     if (fn_type_id.return_type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
-    depends_on_compile_var = depends_on_compile_var || return_type_value->static_value.depends_on_compile_var;
+    depends_on_compile_var = depends_on_compile_var || return_type_value->value.depends_on_compile_var;
 
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
     out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
@@ -9840,7 +9870,7 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
 
 static TypeTableEntry *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) {
     IrInstruction *value = instruction->value->other;
-    if (value->type_entry->id == TypeTableEntryIdInvalid)
+    if (value->value.type->id == TypeTableEntryIdInvalid)
         return ira->codegen->builtin_types.entry_invalid;
 
     ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
@@ -9851,6 +9881,11 @@ static TypeTableEntry *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrIn
 static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
+        case IrInstructionIdPointerReinterpret:
+        case IrInstructionIdStructInit:
+        case IrInstructionIdStructFieldPtr:
+        case IrInstructionIdEnumFieldPtr:
+        case IrInstructionIdInitEnum:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
@@ -9996,10 +10031,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
         case IrInstructionIdErrWrapCode:
         case IrInstructionIdErrWrapPayload:
         case IrInstructionIdCast:
-        case IrInstructionIdStructFieldPtr:
-        case IrInstructionIdEnumFieldPtr:
-        case IrInstructionIdStructInit:
-        case IrInstructionIdInitEnum:
             zig_panic("TODO analyze more instructions");
     }
     zig_unreachable();
@@ -10007,9 +10038,9 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
 
 static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
     TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
-    instruction->type_entry = instruction_type;
+    instruction->value.type = instruction_type;
     if (instruction->other) {
-        instruction->other->type_entry = instruction_type;
+        instruction->other->value.type = instruction_type;
     } else {
         assert(instruction_type->id == TypeTableEntryIdInvalid ||
                instruction_type->id == TypeTableEntryIdUnreachable);
@@ -10156,6 +10187,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdFnProto:
         case IrInstructionIdTestComptime:
         case IrInstructionIdInitEnum:
+        case IrInstructionIdPointerReinterpret:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -5,6 +5,7 @@
  * See http://opensource.org/licenses/MIT
  */
 
+#include "analyze.hpp"
 #include "ir.hpp"
 #include "ir_print.hpp"
 
@@ -24,13 +25,13 @@ static void ir_print_indent(IrPrint *irp) {
 
 static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
     ir_print_indent(irp);
-    const char *type_name = instruction->type_entry ? buf_ptr(&instruction->type_entry->name) : "(unknown)";
+    const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)";
     const char *ref_count = ir_has_side_effects(instruction) ?
         "-" : buf_ptr(buf_sprintf("%zu", instruction->ref_count));
     fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count);
 }
 
-static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, ConstExprValue *const_val) {
+static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
     switch (const_val->special) {
         case ConstValSpecialRuntime:
             zig_unreachable();
@@ -43,9 +44,12 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
         case ConstValSpecialStatic:
             break;
     }
-    switch (type_entry->id) {
+    assert(const_val->type);
+
+    TypeTableEntry *canon_type = get_underlying_type(const_val->type);
+    switch (canon_type->id) {
         case TypeTableEntryIdTypeDecl:
-            return ir_print_const_value(irp, type_entry->data.type_decl.canonical_type, const_val);
+            zig_unreachable();
         case TypeTableEntryIdInvalid:
             fprintf(irp->f, "(invalid)");
             return;
@@ -94,7 +98,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
             }
         case TypeTableEntryIdPointer:
             fprintf(irp->f, "&");
-            ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val));
+            ir_print_const_value(irp, const_ptr_pointee(const_val));
             return;
         case TypeTableEntryIdFn:
             {
@@ -110,14 +114,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
             }
         case TypeTableEntryIdArray:
             {
-                uint64_t len = type_entry->data.array.len;
-                fprintf(irp->f, "%s{", buf_ptr(&type_entry->name));
+                uint64_t len = canon_type->data.array.len;
+                fprintf(irp->f, "%s{", buf_ptr(&canon_type->name));
                 for (uint64_t i = 0; i < len; i += 1) {
                     if (i != 0)
                         fprintf(irp->f, ",");
                     ConstExprValue *child_value = &const_val->data.x_array.elements[i];
-                    TypeTableEntry *child_type = type_entry->data.array.child_type;
-                    ir_print_const_value(irp, child_type, child_value);
+                    ir_print_const_value(irp, child_value);
                 }
                 fprintf(irp->f, "}");
                 return;
@@ -135,7 +138,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
         case TypeTableEntryIdMaybe:
             {
                 if (const_val->data.x_maybe) {
-                    ir_print_const_value(irp, type_entry->data.maybe.child_type, const_val->data.x_maybe);
+                    ir_print_const_value(irp, const_val->data.x_maybe);
                 } else {
                     fprintf(irp->f, "null");
                 }
@@ -160,22 +163,22 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
             }
         case TypeTableEntryIdStruct:
             {
-                fprintf(irp->f, "(struct %s constant)", buf_ptr(&type_entry->name));
+                fprintf(irp->f, "(struct %s constant)", buf_ptr(&canon_type->name));
                 return;
             }
         case TypeTableEntryIdEnum:
             {
-                fprintf(irp->f, "(enum %s constant)", buf_ptr(&type_entry->name));
+                fprintf(irp->f, "(enum %s constant)", buf_ptr(&canon_type->name));
                 return;
             }
         case TypeTableEntryIdErrorUnion:
             {
-                fprintf(irp->f, "(error union %s constant)", buf_ptr(&type_entry->name));
+                fprintf(irp->f, "(error union %s constant)", buf_ptr(&canon_type->name));
                 return;
             }
         case TypeTableEntryIdUnion:
             {
-                fprintf(irp->f, "(union %s constant)", buf_ptr(&type_entry->name));
+                fprintf(irp->f, "(union %s constant)", buf_ptr(&canon_type->name));
                 return;
             }
         case TypeTableEntryIdPureError:
@@ -185,7 +188,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
             }
         case TypeTableEntryIdEnumTag:
             {
-                TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
+                TypeTableEntry *enum_type = canon_type->data.enum_tag.enum_type;
                 TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint];
                 fprintf(irp->f, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
                 return;
@@ -194,19 +197,13 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
     zig_unreachable();
 }
 
-static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) {
-    TypeTableEntry *type_entry = instruction->type_entry;
-    ConstExprValue *const_val = &instruction->static_value;
-    ir_print_const_value(irp, type_entry, const_val);
-}
-
 static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
     fprintf(irp->f, "#%zu", instruction->debug_id);
 }
 
 static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
-    if (instruction->static_value.special != ConstValSpecialRuntime) {
-        ir_print_const_instruction(irp, instruction);
+    if (instruction->value.special != ConstValSpecialRuntime) {
+        ir_print_const_value(irp, &instruction->value);
     } else {
         ir_print_var_instruction(irp, instruction);
     }
@@ -223,7 +220,7 @@ static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instructio
 }
 
 static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
-    ir_print_const_instruction(irp, &const_instruction->base);
+    ir_print_const_value(irp, &const_instruction->base.value);
 }
 
 static const char *ir_bin_op_id_str(IrBinOp op_id) {
@@ -925,6 +922,12 @@ static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction)
     fprintf(irp->f, "}");
 }
 
+static void ir_print_pointer_reinterpret(IrPrint *irp, IrInstructionPointerReinterpret *instruction) {
+    fprintf(irp->f, "(%s)(", buf_ptr(&instruction->base.value.type->name));
+    ir_print_other_instruction(irp, instruction->ptr);
+    fprintf(irp->f, ")");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1164,6 +1167,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdInitEnum:
             ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
             break;
+        case IrInstructionIdPointerReinterpret:
+            ir_print_pointer_reinterpret(irp, (IrInstructionPointerReinterpret *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
@@ -1188,14 +1194,14 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
 static void print_tld_var(IrPrint *irp, TldVar *tld_var) {
     const char *const_or_var = tld_var->var->src_is_const ? "const" : "var";
     fprintf(irp->f, "%s %s", const_or_var, buf_ptr(tld_var->base.name));
-    bool omit_type = (tld_var->var->type->id == TypeTableEntryIdNumLitFloat ||
-        tld_var->var->type->id == TypeTableEntryIdNumLitInt);
+    bool omit_type = (tld_var->var->value.type->id == TypeTableEntryIdNumLitFloat ||
+        tld_var->var->value.type->id == TypeTableEntryIdNumLitInt);
     if (!omit_type) {
-        fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->type->name));
+        fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->value.type->name));
     }
-    if (tld_var->var->value) {
+    if (tld_var->var->value.special != ConstValSpecialRuntime) {
         fprintf(irp->f, " = ");
-        ir_print_const_value(irp, tld_var->var->type, tld_var->var->value);
+        ir_print_const_value(irp, &tld_var->var->value);
     }
     fprintf(irp->f, ";\n");
 }
src/parseh.cpp
@@ -124,51 +124,52 @@ static void parseh_init_tld(Context *c, Tld *tld, TldId id, Buf *name) {
     tld->resolution = TldResolutionOk;
 }
 
-static TldVar *create_global_var(Context *c, Buf *name, TypeTableEntry *var_type, ConstExprValue *var_value, bool is_const) {
+static TldVar *create_global_var(Context *c, Buf *name, ConstExprValue *var_value, bool is_const) {
     TldVar *tld_var = allocate<TldVar>(1);
     parseh_init_tld(c, &tld_var->base, TldIdVar, name);
-    tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, var_type, is_const, var_value);
+    tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, is_const, var_value);
     return tld_var;
 }
 
 static Tld *create_global_char_lit_var(Context *c, Buf *name, uint8_t value) {
-    TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_u8,
-        create_const_unsigned_negative(value, false), true);
+    ConstExprValue *var_val = create_const_unsigned_negative(c->codegen->builtin_types.entry_u8, value, false);
+    TldVar *tld_var = create_global_var(c, name, var_val, true);
     return &tld_var->base;
 }
 
 static Tld *create_global_str_lit_var(Context *c, Buf *name, Buf *value) {
-    TypeTableEntry *str_type = get_array_type(c->codegen, c->codegen->builtin_types.entry_u8, buf_len(value));
-    TldVar *tld_var = create_global_var(c, name, str_type, create_const_str_lit(value), true);
+    TldVar *tld_var = create_global_var(c, name, create_const_str_lit(c->codegen, value), true);
     return &tld_var->base;
 }
 
 static Tld *create_global_num_lit_unsigned_negative(Context *c, Buf *name, uint64_t x, bool negative) {
-    TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int,
-        create_const_unsigned_negative(x, negative), true);
+    ConstExprValue *var_val = create_const_unsigned_negative(c->codegen->builtin_types.entry_num_lit_int, x, negative);
+    TldVar *tld_var = create_global_var(c, name, var_val, true);
     return &tld_var->base;
 }
 
 static Tld *create_global_num_lit_float(Context *c, Buf *name, double value) {
-    TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_float,
-        create_const_float(value), true);
+    ConstExprValue *var_val = create_const_float(c->codegen->builtin_types.entry_num_lit_float, value);
+    TldVar *tld_var = create_global_var(c, name, var_val, true);
     return &tld_var->base;
 }
 
-static ConstExprValue *create_const_num_lit_ap(Context *c, const Decl *source_decl, const llvm::APSInt &aps_int) {
+static ConstExprValue *create_const_int_ap(Context *c, TypeTableEntry *type, const Decl *source_decl,
+        const llvm::APSInt &aps_int)
+{
     if (aps_int.isSigned()) {
         if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
             emit_warning(c, source_decl, "integer overflow\n");
             return nullptr;
         } else {
-            return create_const_signed(aps_int.getExtValue());
+            return create_const_signed(type, aps_int.getExtValue());
         }
     } else {
         if (aps_int > INT64_MAX) {
             emit_warning(c, source_decl, "integer overflow\n");
             return nullptr;
         } else {
-            return create_const_unsigned_negative(aps_int.getExtValue(), false);
+            return create_const_unsigned_negative(type, aps_int.getExtValue(), false);
         }
     }
 }
@@ -176,19 +177,18 @@ static ConstExprValue *create_const_num_lit_ap(Context *c, const Decl *source_de
 static Tld *create_global_num_lit_ap(Context *c, const Decl *source_decl, Buf *name,
         const llvm::APSInt &aps_int)
 {
-    ConstExprValue *const_value = create_const_num_lit_ap(c, source_decl, aps_int);
+    ConstExprValue *const_value = create_const_int_ap(c, c->codegen->builtin_types.entry_num_lit_int,
+            source_decl, aps_int);
     if (!const_value)
         return nullptr;
-    TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int, const_value, true);
+    TldVar *tld_var = create_global_var(c, name, const_value, true);
     return &tld_var->base;
 }
 
 
 static Tld *add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) {
-    ConstExprValue *var_value = allocate<ConstExprValue>(1);
-    var_value->special = ConstValSpecialStatic;
-    var_value->data.x_type = type_entry;
-    TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_type, var_value, true);
+    ConstExprValue *var_value = create_const_type(c->codegen, type_entry);
+    TldVar *tld_var = create_global_var(c, name, var_value, true);
     add_global(c, &tld_var->base);
 
     c->global_type_table.put(name, type_entry);
@@ -1025,7 +1025,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
                             "ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name));
                         return;
                     }
-                    init_value = create_const_num_lit_ap(c, var_decl, ap_value->getInt());
+                    init_value = create_const_int_ap(c, var_type, var_decl, ap_value->getInt());
                     if (!init_value)
                         return;
 
@@ -1047,13 +1047,13 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
                 return;
         }
 
-        TldVar *tld_var = create_global_var(c, name, var_type, init_value, true);
+        TldVar *tld_var = create_global_var(c, name, init_value, true);
         add_global(c, &tld_var->base);
         return;
     }
 
     if (is_extern) {
-        TldVar *tld_var = create_global_var(c, name, var_type, nullptr, is_const);
+        TldVar *tld_var = create_global_var(c, name, create_const_runtime(var_type), is_const);
         tld_var->var->is_extern = true;
         add_global(c, &tld_var->base);
         return;
@@ -1199,7 +1199,7 @@ static void process_symbol_macros(Context *c) {
         // variable is non-null and calls it.
         if (existing_tld->id == TldIdVar) {
             TldVar *tld_var = (TldVar *)existing_tld;
-            TypeTableEntry *var_type = tld_var->var->type;
+            TypeTableEntry *var_type = tld_var->var->value.type;
             if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) {
                 TypeTableEntry *child_type = var_type->data.maybe.child_type;
                 if (child_type->id == TypeTableEntryIdFn) {
test/cases3/misc.zig
@@ -261,6 +261,16 @@ fn typeEquality() {
     assert(&const u8 != &u8);
 }
 
+
+const global_a: i32 = 1234;
+const global_b: &const i32 = &global_a;
+const global_c: &const f32 = (&const f32)(global_b);
+fn compileTimeGlobalReinterpret() {
+    @setFnTest(this);
+    const d = (&const i32)(global_c);
+    assert(*d == 1234);
+}
+
 // TODO import from std.str
 pub fn memeql(a: []const u8, b: []const u8) -> bool {
     sliceEql(u8, a, b)
@@ -288,7 +298,6 @@ pub fn cstrcmp(a: &const u8, b: &const u8) -> i8 {
     };
 }
 
-
 // TODO const assert = @import("std").debug.assert;
 fn assert(ok: bool) {
     if (!ok)
test/self_hosted.zig
@@ -9,27 +9,12 @@ const test_enum_with_members = @import("cases/enum_with_members.zig");
 
 
 fn explicitCastMaybePointers() {
-    @setFnTest(this, true);
+    @setFnTest(this);
 
     const a: ?&i32 = undefined;
     const b: ?&f32 = (?&f32)(a);
 }
 
-
-fn multilineCString() {
-    @setFnTest(this);
-
-    const s1 =
-        c\\one
-        c\\two)
-        c\\three
-    ;
-    const s2 = c"one\ntwo)\nthree";
-    assert(cstr.cmp(s1, s2) == 0);
-}
-
-
-
 fn genericMallocFree() {
     @setFnTest(this, true);