Commit ee5064c053

Andrew Kelley <andrew@ziglang.org>
2019-03-29 23:32:16
decouple llvm types from zig types
Not tested yet, but it builds. This closes #761, and lays the groundwork for fixing the remaining false positive "foo depends on itself" bugs, such as #624. It also lays the groundwork for implementing ability to specify alignment of fields (#1512).
1 parent 2f96c55
src/all_types.hpp
@@ -1067,8 +1067,10 @@ struct TypeStructField {
     ZigType *type_entry;
     size_t src_index;
     size_t gen_index;
-    uint32_t bit_offset_in_host; // offset from the memory at gen_index
+    size_t offset; // byte offset from beginning of struct
     AstNode *decl_node;
+    uint32_t bit_offset_in_host; // offset from the memory at gen_index
+    uint32_t host_int_bytes; // size of host integer
 };
 
 enum ResolveStatus {
@@ -1101,14 +1103,13 @@ struct ZigTypeStruct {
     AstNode *decl_node;
     TypeStructField *fields;
     ScopeDecls *decls_scope;
-    uint64_t size_bytes;
     HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
     RootStruct *root_struct;
+    uint32_t *host_int_bytes; // available for packed structs, indexed by gen_index
 
     uint32_t src_field_count;
     uint32_t gen_field_count;
 
-    uint32_t abi_alignment; // known after ResolveStatusAlignmentKnown
     ContainerLayout layout;
     ResolveStatus resolve_status;
 
@@ -1164,39 +1165,28 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b);
 
 struct ZigTypeUnion {
     AstNode *decl_node;
-    ContainerLayout layout;
-    uint32_t src_field_count;
-    uint32_t gen_field_count;
     TypeUnionField *fields;
-    bool is_invalid; // true if any fields are invalid
+    ScopeDecls *decls_scope;
+    HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name;
     ZigType *tag_type; // always an enum or null
-    LLVMTypeRef union_type_ref;
+    LLVMTypeRef union_llvm_type;
+    ZigType *most_aligned_union_member;
+    size_t gen_union_index;
+    size_t gen_tag_index;
+    size_t union_abi_size;
 
-    ScopeDecls *decls_scope;
+    uint32_t src_field_count;
+    uint32_t gen_field_count;
 
-    // set this flag temporarily to detect infinite loops
-    bool embedded_in_current;
-    bool reported_infinite_err;
-    // whether we've finished resolving it
-    bool complete;
+    ContainerLayout layout;
+    ResolveStatus resolve_status;
 
+    bool have_explicit_tag_type;
+    bool resolve_loop_flag; // set this flag temporarily to detect infinite loops
+    bool reported_infinite_err;
     // whether any of the fields require comptime
     // the value is not valid until zero_bits_known == true
     bool requires_comptime;
-
-    bool zero_bits_loop_flag;
-    bool zero_bits_known;
-    uint32_t abi_alignment; // also figured out with zero_bits pass
-
-    size_t gen_union_index;
-    size_t gen_tag_index;
-
-    bool have_explicit_tag_type;
-
-    uint32_t union_size_bytes;
-    ZigType *most_aligned_union_member;
-
-    HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name;
 };
 
 struct FnGenParamInfo {
@@ -1277,8 +1267,11 @@ struct ZigType {
     ZigTypeId id;
     Buf name;
 
-    LLVMTypeRef type_ref;
-    ZigLLVMDIType *di_type;
+    // These are not supposed to be accessed directly. They're
+    // null during semantic analysis, memoized with get_llvm_type
+    // and get_llvm_di_type
+    LLVMTypeRef llvm_type;
+    ZigLLVMDIType *llvm_di_type;
 
     union {
         ZigTypePointer pointer;
@@ -1308,8 +1301,14 @@ struct ZigType {
     ConstExprValue *cached_const_name_val;
 
     OnePossibleValue one_possible_value;
+    // Known after ResolveStatusAlignmentKnown.
+    uint32_t abi_align;
+    // The offset in bytes between consecutive array elements of this type. Known
+    // after ResolveStatusSizeKnown.
+    size_t abi_size;
+    // Number of bits of information in this type. Known after ResolveStatusSizeKnown.
+    size_t size_in_bits;
 
-    bool zero_bits; // this is denormalized data
     bool gen_h_loop_flag;
 };
 
@@ -1700,11 +1699,9 @@ struct CodeGen {
     ZigList<AstNode *> use_queue;
     size_t use_queue_index;
     ZigList<TimeEvent> timing_events;
-    ZigList<ZigLLVMDIType **> error_di_types;
     ZigList<AstNode *> tld_ref_source_node_stack;
     ZigList<ZigFn *> inline_fns;
     ZigList<ZigFn *> test_fns;
-    ZigList<ZigLLVMDIEnumerator *> err_enumerators;
     ZigList<ErrorTableEntry *> errors_by_index;
     ZigList<CacheHash *> caches_to_release;
     size_t largest_err_name_len;
src/analyze.cpp
@@ -26,6 +26,7 @@ static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *st
 static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type);
 static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type);
 static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type);
+static Error ATTRIBUTE_MUST_USE resolve_union_alignment(CodeGen *g, ZigType *union_type);
 static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry);
 
 static bool is_top_level_struct(ZigType *import) {
@@ -264,6 +265,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
             zig_unreachable();
         case ZigTypeIdStruct:
             return type_entry->data.structure.resolve_status >= status;
+        case ZigTypeIdUnion:
+            return type_entry->data.unionation.resolve_status >= status;
         case ZigTypeIdEnum:
             switch (status) {
                 case ResolveStatusUnstarted:
@@ -278,20 +281,6 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
                     return type_entry->data.enumeration.complete;
             }
             zig_unreachable();
-        case ZigTypeIdUnion:
-            switch (status) {
-                case ResolveStatusUnstarted:
-                    return true;
-                case ResolveStatusInvalid:
-                    zig_unreachable();
-                case ResolveStatusZeroBitsKnown:
-                    return type_entry->data.unionation.zero_bits_known;
-                case ResolveStatusAlignmentKnown:
-                    return type_entry->data.unionation.zero_bits_known;
-                case ResolveStatusSizeKnown:
-                    return type_entry->data.unionation.complete;
-            }
-            zig_unreachable();
         case ZigTypeIdOpaque:
             return status < ResolveStatusSizeKnown;
         case ZigTypeIdMetaType:
@@ -325,49 +314,18 @@ bool type_is_complete(ZigType *type_entry) {
 }
 
 uint64_t type_size(CodeGen *g, ZigType *type_entry) {
-    assert(type_is_complete(type_entry));
-
-    if (!type_has_bits(type_entry))
-        return 0;
-
-    if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) {
-        uint64_t size_in_bits = type_size_bits(g, type_entry);
-        return (size_in_bits + 7) / 8;
-    } else if (type_entry->id == ZigTypeIdArray) {
-        ZigType *child_type = type_entry->data.array.child_type;
-        if (child_type->id == ZigTypeIdStruct &&
-            child_type->data.structure.layout == ContainerLayoutPacked)
-        {
-            uint64_t size_in_bits = type_size_bits(g, type_entry);
-            return (size_in_bits + 7) / 8;
-        }
-    }
-
-    return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
+    assert(type_is_resolved(type_entry, ResolveStatusSizeKnown));
+    return type_entry->abi_size;
 }
 
 uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
-    assert(type_is_complete(type_entry));
-
-    if (!type_has_bits(type_entry))
-        return 0;
-
-    if (type_entry->id == ZigTypeIdStruct) {
-        if (type_entry->data.structure.layout == ContainerLayoutPacked) {
-            uint64_t result = 0;
-            for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
-                result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);
-            }
-            return result;
-        } else if (type_entry->data.structure.layout == ContainerLayoutExtern) {
-            return type_size(g, type_entry) * 8;
-        }
-    } else if (type_entry->id == ZigTypeIdArray) {
-        ZigType *child_type = type_entry->data.array.child_type;
-        return type_entry->data.array.len * type_size_bits(g, child_type);
-    }
+    assert(type_is_resolved(type_entry, ResolveStatusSizeKnown));
+    return type_entry->size_in_bits;
+}
 
-    return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);
+uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) {
+    assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown));
+    return type_entry->abi_align;
 }
 
 static bool is_slice(ZigType *type) {
@@ -385,16 +343,14 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
         return g->builtin_types.entry_promise;
     }
 
-    ZigType *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
     ZigType *entry = new_type_table_entry(ZigTypeIdPromise);
-    entry->type_ref = u8_ptr_type->type_ref;
-    entry->zero_bits = false;
+    entry->abi_size = g->pointer_size_bytes;
+    entry->size_in_bits = g->pointer_size_bytes * 8;
     entry->data.promise.result_type = result_type;
     buf_init_from_str(&entry->name, "promise");
     if (result_type != nullptr) {
         buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
     }
-    entry->di_type = u8_ptr_type->di_type;
 
     if (result_type != nullptr) {
         result_type->promise_parent = entry;
@@ -496,36 +452,15 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
 
     assert(child_type->id != ZigTypeIdInvalid);
 
-    entry->zero_bits = !type_has_bits(child_type);
-
-    if (!entry->zero_bits) {
-        if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
-            bit_offset_in_host != 0 || allow_zero)
-        {
-            ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false,
-                    PtrLenSingle, 0, 0, host_int_bytes, false);
-            entry->type_ref = peer_type->type_ref;
-            entry->di_type = peer_type->di_type;
-        } else {
-            if (host_int_bytes == 0) {
-                entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
-                uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-                uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
-                assert(child_type->di_type);
-                entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, child_type->di_type,
-                        debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
-            } else {
-                ZigType *host_int_type = get_int_type(g, false, host_int_bytes * 8);
-                entry->type_ref = LLVMPointerType(host_int_type->type_ref, 0);
-                uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, host_int_type->type_ref);
-                uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, host_int_type->type_ref);
-                entry->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, host_int_type->di_type,
-                        debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
-            }
-        }
+    if (type_has_bits(child_type)) {
+        entry->abi_size = g->builtin_types.entry_usize->abi_size;
+        entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+        entry->abi_align = g->builtin_types.entry_usize->abi_align;
     } else {
         assert(byte_alignment == 0);
-        entry->di_type = g->builtin_types.entry_void->di_type;
+        entry->abi_size = 0;
+        entry->size_in_bits = 0;
+        entry->abi_align = 0;
     }
 
     entry->data.pointer.ptr_len = ptr_len;
@@ -586,89 +521,61 @@ ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
 }
 
 ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
-    if (child_type->optional_parent) {
-        ZigType *entry = child_type->optional_parent;
-        return entry;
+    if (child_type->optional_parent != nullptr) {
+        return child_type->optional_parent;
+    }
+
+    assert(type_is_resolved(child_type, ResolveStatusSizeKnown));
+
+    ZigType *entry = new_type_table_entry(ZigTypeIdOptional);
+
+    buf_resize(&entry->name, 0);
+    buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
+
+    if (!type_has_bits(child_type)) {
+        entry->size_in_bits = g->builtin_types.entry_bool->size_in_bits;
+        entry->abi_size = g->builtin_types.entry_bool->abi_size;
+        entry->abi_align = g->builtin_types.entry_bool->abi_align;
+    } else if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) {
+        // This is an optimization but also is necessary for calling C
+        // functions where all pointers are optional pointers.
+        // Function types are technically pointers.
+        entry->size_in_bits = child_type->size_in_bits;
+        entry->abi_size = child_type->abi_size;
+        entry->abi_align = child_type->abi_align;
     } else {
-        assertNoError(ensure_complete_type(g, child_type));
-
-        ZigType *entry = new_type_table_entry(ZigTypeIdOptional);
-        assert(child_type->type_ref || child_type->zero_bits);
-
-        buf_resize(&entry->name, 0);
-        buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
-
-        if (child_type->zero_bits) {
-            entry->type_ref = LLVMInt1Type();
-            entry->di_type = g->builtin_types.entry_bool->di_type;
-        } else if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) {
-            assert(child_type->di_type);
-            // this is an optimization but also is necessary for calling C
-            // functions where all pointers are maybe pointers
-            // function types are technically pointers
-            entry->type_ref = child_type->type_ref;
-            entry->di_type = child_type->di_type;
-            if (entry->di_type == g->builtin_types.entry_global_error_set->di_type) {
-                g->error_di_types.append(&entry->di_type);
-            }
-        } else {
-            assert(child_type->di_type);
-            // create a struct with a boolean whether this is the null value
-            LLVMTypeRef elem_types[] = {
-                child_type->type_ref,
-                LLVMInt1Type(),
-            };
-            entry->type_ref = LLVMStructType(elem_types, 2, false);
-
-
-            ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
-            ZigLLVMDIFile *di_file = nullptr;
-            unsigned line = 0;
-            entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-                ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
-                compile_unit_scope, di_file, line);
-
-            uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
-            uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref);
-            uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
-            ZigType *bool_type = g->builtin_types.entry_bool;
-            uint64_t maybe_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, bool_type->type_ref);
-            uint64_t maybe_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, bool_type->type_ref);
-            uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
-
-            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
-
-            ZigLLVMDIType *di_element_types[] = {
-                ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                        "val", di_file, line,
-                        val_debug_size_in_bits,
-                        val_debug_align_in_bits,
-                        val_offset_in_bits,
-                        0, child_type->di_type),
-                ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                        "maybe", di_file, line,
-                        maybe_debug_size_in_bits,
-                        maybe_debug_align_in_bits,
-                        maybe_offset_in_bits,
-                        0, bool_type->di_type),
-            };
-            ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                    compile_unit_scope,
-                    buf_ptr(&entry->name),
-                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
-                    nullptr, di_element_types, 2, 0, nullptr, "");
-
-            ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
-            entry->di_type = replacement_di_type;
-        }
-
-        entry->data.maybe.child_type = child_type;
-
-        child_type->optional_parent = entry;
-        return entry;
+        // This value only matters if the type is legal in a packed struct, which is not
+        // true for optional types which did not fit the above 2 categories (zero bit child type,
+        // or nonnull ptr child type, or error set child type).
+        entry->size_in_bits = child_type->size_in_bits + 1;
+
+        // We're going to make a struct with the child type as the first field,
+        // and a bool as the second. Since the child type's abi alignment is guaranteed
+        // to be >= the bool's abi size (1 byte), the added size is exactly equal to the
+        // child type's ABI alignment.
+        assert(child_type->abi_align >= g->builtin_types.entry_bool->abi_size);
+        entry->abi_align = child_type->abi_align;
+        entry->abi_size = child_type->abi_size + child_type->abi_align;
     }
+
+    entry->data.maybe.child_type = child_type;
+
+    child_type->optional_parent = entry;
+    return entry;
+}
+
+static size_t align_forward(size_t addr, size_t alignment) {
+    return (addr + alignment - 1) & ~(alignment - 1);
+}
+
+static size_t next_field_offset(size_t offset, size_t align_from_zero, size_t field_size, size_t field_align) {
+    BREAKPOINT; // TODO test this
+    // Convert offset to a pretend address which has the specified alignment.
+    size_t addr = offset + align_from_zero;
+    // March the address forward to respect the field alignment.
+    size_t aligned_addr = align_forward(addr + field_size, field_align);
+    // Convert back from pretend address to offset.
+    return aligned_addr - align_from_zero;
 }
 
 ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type) {
@@ -686,8 +593,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
     }
 
     ZigType *entry = new_type_table_entry(ZigTypeIdErrorUnion);
-    assert(payload_type->di_type);
-    assert(type_is_complete(payload_type));
+    assert(type_is_resolved(payload_type, ResolveStatusSizeKnown));
 
     buf_resize(&entry->name, 0);
     buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
@@ -697,68 +603,29 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
 
     if (!type_has_bits(payload_type)) {
         if (type_has_bits(err_set_type)) {
-            entry->type_ref = err_set_type->type_ref;
-            entry->di_type = err_set_type->di_type;
-            g->error_di_types.append(&entry->di_type);
+            entry->size_in_bits = err_set_type->size_in_bits;
+            entry->abi_size = err_set_type->abi_size;
+            entry->abi_align = err_set_type->abi_align;
         } else {
-            entry->zero_bits = true;
-            entry->di_type = g->builtin_types.entry_void->di_type;
+            entry->size_in_bits = 0;
+            entry->abi_size = 0;
+            entry->abi_align = 0;
         }
     } else if (!type_has_bits(err_set_type)) {
-        entry->type_ref = payload_type->type_ref;
-        entry->di_type = payload_type->di_type;
+        entry->size_in_bits = payload_type->size_in_bits;
+        entry->abi_size = payload_type->abi_size;
+        entry->abi_align = payload_type->abi_align;
     } else {
-        LLVMTypeRef elem_types[] = {
-            err_set_type->type_ref,
-            payload_type->type_ref,
-        };
-        entry->type_ref = LLVMStructType(elem_types, 2, false);
-
-        ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
-        ZigLLVMDIFile *di_file = nullptr;
-        unsigned line = 0;
-        entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-            ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
-            compile_unit_scope, di_file, line);
-
-        uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_type->type_ref);
-        uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref);
-        uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index);
-
-        uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_type->type_ref);
-        uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref);
-        uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref,
-                err_union_payload_index);
-
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
-
-        ZigLLVMDIType *di_element_types[] = {
-            ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                    "tag", di_file, line,
-                    tag_debug_size_in_bits,
-                    tag_debug_align_in_bits,
-                    tag_offset_in_bits,
-                    0, err_set_type->di_type),
-            ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                    "value", di_file, line,
-                    value_debug_size_in_bits,
-                    value_debug_align_in_bits,
-                    value_offset_in_bits,
-                    0, payload_type->di_type),
-        };
-
-        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                compile_unit_scope,
-                buf_ptr(&entry->name),
-                di_file, line,
-                debug_size_in_bits,
-                debug_align_in_bits,
-                0,
-                nullptr, di_element_types, 2, 0, nullptr, "");
-
-        ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
-        entry->di_type = replacement_di_type;
+        entry->abi_align = max(err_set_type->abi_align, payload_type->abi_align);
+        size_t field_sizes[2];
+        size_t field_aligns[2];
+        field_sizes[err_union_err_index] = err_set_type->abi_size;
+        field_aligns[err_union_err_index] = err_set_type->abi_align;
+        field_sizes[err_union_payload_index] = payload_type->abi_size;
+        field_aligns[err_union_payload_index] = payload_type->abi_align;
+        size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[0]);
+        entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], field_aligns[1]);
+        entry->size_in_bits = entry->abi_size * 8;
     }
 
     g->type_table.put(type_id, entry);
@@ -772,31 +639,20 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
     type_id.data.array.size = array_size;
     auto existing_entry = g->type_table.maybe_get(type_id);
     if (existing_entry) {
-        ZigType *entry = existing_entry->value;
-        return entry;
+        return existing_entry->value;
     }
 
-    assertNoError(ensure_complete_type(g, child_type));
+    assert(type_is_resolved(child_type, ResolveStatusSizeKnown));
 
     ZigType *entry = new_type_table_entry(ZigTypeIdArray);
-    entry->zero_bits = (array_size == 0) || child_type->zero_bits;
 
     buf_resize(&entry->name, 0);
     buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s", array_size, buf_ptr(&child_type->name));
 
-    if (entry->zero_bits) {
-        entry->di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, 0,
-                0, child_type->di_type, 0);
-    } else {
-        entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref,
-                (unsigned int)array_size) : nullptr;
-
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
+    entry->size_in_bits = child_type->size_in_bits * array_size;
+    entry->abi_align = child_type->abi_align;
+    entry->abi_size = child_type->abi_size * array_size;
 
-        entry->di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits,
-                debug_align_in_bits, child_type->di_type, (int)array_size);
-    }
     entry->data.array.child_type = child_type;
     entry->data.array.len = array_size;
 
@@ -804,11 +660,27 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) {
     return entry;
 }
 
-static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *entry) {
+ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
+    assert(ptr_type->id == ZigTypeIdPointer);
+    assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
+
+    ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent;
+    if (*parent_pointer) {
+        return *parent_pointer;
+    }
+
+    ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
+
+    // replace the & with [] to go from a ptr type name to a slice type name
+    buf_resize(&entry->name, 0);
+    size_t name_offset = (ptr_type->data.pointer.ptr_len == PtrLenSingle) ? 1 : 3;
+    buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
+
     unsigned element_count = 2;
     Buf *ptr_field_name = buf_create_from_str("ptr");
     Buf *len_field_name = buf_create_from_str("len");
 
+    entry->data.structure.resolve_status = ResolveStatusSizeKnown;
     entry->data.structure.layout = ContainerLayoutAuto;
     entry->data.structure.is_slice = true;
     entry->data.structure.src_field_count = element_count;
@@ -816,7 +688,7 @@ static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *e
     entry->data.structure.fields = allocate<TypeStructField>(element_count);
     entry->data.structure.fields_by_name.init(element_count);
     entry->data.structure.fields[slice_ptr_index].name = ptr_field_name;
-    entry->data.structure.fields[slice_ptr_index].type_entry = pointer_type;
+    entry->data.structure.fields[slice_ptr_index].type_entry = ptr_type;
     entry->data.structure.fields[slice_ptr_index].src_index = slice_ptr_index;
     entry->data.structure.fields[slice_ptr_index].gen_index = 0;
     entry->data.structure.fields[slice_len_index].name = len_field_name;
@@ -827,28 +699,11 @@ static void slice_type_common_init(CodeGen *g, ZigType *pointer_type, ZigType *e
     entry->data.structure.fields_by_name.put(ptr_field_name, &entry->data.structure.fields[slice_ptr_index]);
     entry->data.structure.fields_by_name.put(len_field_name, &entry->data.structure.fields[slice_len_index]);
 
-    if (!type_has_bits(pointer_type->data.pointer.child_type)) {
+    if (!type_has_bits(ptr_type)) {
         entry->data.structure.gen_field_count = 1;
         entry->data.structure.fields[slice_ptr_index].gen_index = SIZE_MAX;
         entry->data.structure.fields[slice_len_index].gen_index = 0;
     }
-}
-
-ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
-    assert(ptr_type->id == ZigTypeIdPointer);
-    assert(ptr_type->data.pointer.ptr_len == PtrLenUnknown);
-
-    ZigType **parent_pointer = &ptr_type->data.pointer.slice_parent;
-    if (*parent_pointer) {
-        return *parent_pointer;
-    }
-
-    ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
-
-    // replace the & with [] to go from a ptr type name to a slice type name
-    buf_resize(&entry->name, 0);
-    size_t name_offset = (ptr_type->data.pointer.ptr_len == PtrLenSingle) ? 1 : 3;
-    buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset);
 
     ZigType *child_type = ptr_type->data.pointer.child_type;
     if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
@@ -858,134 +713,24 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
                 PtrLenUnknown, 0, 0, 0, false);
         ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
 
-        slice_type_common_init(g, ptr_type, entry);
-
-        entry->type_ref = peer_slice_type->type_ref;
-        entry->di_type = peer_slice_type->di_type;
-        entry->data.structure.resolve_status = ResolveStatusSizeKnown;
-        entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
+        entry->size_in_bits = peer_slice_type->size_in_bits;
+        entry->abi_size = peer_slice_type->abi_size;
+        entry->abi_align = peer_slice_type->abi_align;
 
         *parent_pointer = entry;
         return entry;
     }
 
-    // If the child type is []const T then we need to make sure the type ref
-    // and debug info is the same as if the child type were []T.
-    if (is_slice(child_type)) {
-        ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
-        assert(child_ptr_type->id == ZigTypeIdPointer);
-        if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
-            child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
-        {
-            ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
-            ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
-                    PtrLenUnknown, 0, 0, 0, false);
-            ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
-            ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
-                    PtrLenUnknown, 0, 0, 0, false);
-            ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
-
-            entry->type_ref = peer_slice_type->type_ref;
-            entry->di_type = peer_slice_type->di_type;
-            entry->data.structure.abi_alignment = peer_slice_type->data.structure.abi_alignment;
-        }
-    }
-
-    slice_type_common_init(g, ptr_type, entry);
-
-    if (!entry->type_ref) {
-        entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
-
-        ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
-        ZigLLVMDIFile *di_file = nullptr;
-        unsigned line = 0;
-        entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-            ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
-            compile_unit_scope, di_file, line);
-
-        if (child_type->zero_bits) {
-            LLVMTypeRef element_types[] = {
-                g->builtin_types.entry_usize->type_ref,
-            };
-            LLVMStructSetBody(entry->type_ref, element_types, 1, false);
-
-            ZigType *usize_type = g->builtin_types.entry_usize;
-            uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
-            uint64_t len_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
-            uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
-            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-            uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
-
-            ZigLLVMDIType *di_element_types[] = {
-                ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                        "len", di_file, line,
-                        len_debug_size_in_bits,
-                        len_debug_align_in_bits,
-                        len_offset_in_bits,
-                        0, usize_type->di_type),
-            };
-            ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                    compile_unit_scope,
-                    buf_ptr(&entry->name),
-                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
-                    nullptr, di_element_types, 1, 0, nullptr, "");
-
-            ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
-            entry->di_type = replacement_di_type;
-
-            entry->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
-        } else {
-            unsigned element_count = 2;
-            LLVMTypeRef element_types[] = {
-                ptr_type->type_ref,
-                g->builtin_types.entry_usize->type_ref,
-            };
-            LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
-
-
-            uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, ptr_type->type_ref);
-            uint64_t ptr_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, ptr_type->type_ref);
-            uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
-
-            ZigType *usize_type = g->builtin_types.entry_usize;
-            uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, usize_type->type_ref);
-            uint64_t len_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, usize_type->type_ref);
-            uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
-
-            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-            uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
-
-            ZigLLVMDIType *di_element_types[] = {
-                ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                        "ptr", di_file, line,
-                        ptr_debug_size_in_bits,
-                        ptr_debug_align_in_bits,
-                        ptr_offset_in_bits,
-                        0, ptr_type->di_type),
-                ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
-                        "len", di_file, line,
-                        len_debug_size_in_bits,
-                        len_debug_align_in_bits,
-                        len_offset_in_bits,
-                        0, usize_type->di_type),
-            };
-            ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                    compile_unit_scope,
-                    buf_ptr(&entry->name),
-                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
-                    nullptr, di_element_types, 2, 0, nullptr, "");
-
-            ZigLLVMReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
-            entry->di_type = replacement_di_type;
-
-            entry->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref);
-        }
+    if (type_has_bits(ptr_type)) {
+        entry->size_in_bits = ptr_type->size_in_bits + g->builtin_types.entry_usize->size_in_bits;
+        entry->abi_size = ptr_type->abi_size + g->builtin_types.entry_usize->abi_size;
+        entry->abi_align = ptr_type->abi_align;
+    } else {
+        entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+        entry->abi_size = g->builtin_types.entry_usize->abi_size;
+        entry->abi_align = g->builtin_types.entry_usize->abi_align;
     }
 
-
-    entry->data.structure.resolve_status = ResolveStatusSizeKnown;
-
     *parent_pointer = entry;
     return entry;
 }
@@ -998,15 +743,20 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c
     ZigType *import = scope ? get_scope_import(scope) : nullptr;
     unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
 
-    entry->type_ref = LLVMInt8Type();
-    entry->di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
+    entry->llvm_type = LLVMInt8Type();
+    entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
         ZigLLVMTag_DW_structure_type(), full_name,
         import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
         import ? import->data.structure.root_struct->di_file : nullptr,
         line);
-    entry->zero_bits = false;
     entry->data.opaque.bare_name = bare_name;
 
+    // The actual size is unknown, but the value must not be 0 because that
+    // is how type_has_bits is determined.
+    entry->abi_size = SIZE_MAX;
+    entry->size_in_bits = SIZE_MAX;
+    entry->abi_align = 1;
+
     return entry;
 }
 
@@ -1018,7 +768,9 @@ ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) {
 
     ZigType *bound_fn_type = new_type_table_entry(ZigTypeIdBoundFn);
     bound_fn_type->data.bound_fn.fn_type = fn_type;
-    bound_fn_type->zero_bits = true;
+    bound_fn_type->abi_size = 0;
+    bound_fn_type->size_in_bits = 0;
+    bound_fn_type->abi_align = 0;
 
     buf_resize(&bound_fn_type->name, 0);
     buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name));
@@ -1114,8 +866,6 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
     ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);
     fn_type->data.fn.fn_type_id = *fn_type_id;
 
-    bool skip_debug_info = false;
-
     // populate the name of the type
     buf_resize(&fn_type->name, 0);
     if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
@@ -1133,8 +883,6 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
         const char *comma = (i == 0) ? "" : ", ";
         const char *noalias_str = param_info->is_noalias ? "noalias " : "";
         buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(&param_type->name));
-
-        skip_debug_info = skip_debug_info || !param_type->di_type;
     }
 
     if (fn_type_id->is_var_args) {
@@ -1146,116 +894,11 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
         buf_appendf(&fn_type->name, " align(%" PRIu32 ")", fn_type_id->alignment);
     }
     buf_appendf(&fn_type->name, " %s", buf_ptr(&fn_type_id->return_type->name));
-    skip_debug_info = skip_debug_info || !fn_type_id->return_type->di_type;
-
-    // next, loop over the parameters again and compute debug information
-    // and codegen information
-    if (!skip_debug_info) {
-        bool first_arg_return = want_first_arg_sret(g, fn_type_id);
-        bool is_async = fn_type_id->cc == CallingConventionAsync;
-        bool is_c_abi = fn_type_id->cc == CallingConventionC;
-        bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
-        // +1 for maybe making the first argument the return value
-        // +1 for maybe first argument the error return trace
-        // +2 for maybe arguments async allocator and error code pointer
-        ZigList<LLVMTypeRef> gen_param_types = {};
-        // +1 because 0 is the return type and
-        // +1 for maybe making first arg ret val and
-        // +1 for maybe first argument the error return trace
-        // +2 for maybe arguments async allocator and error code pointer
-        ZigList<ZigLLVMDIType *> param_di_types = {};
-        param_di_types.append(fn_type_id->return_type->di_type);
-        ZigType *gen_return_type;
-        if (is_async) {
-            gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
-        } else if (!type_has_bits(fn_type_id->return_type)) {
-            gen_return_type = g->builtin_types.entry_void;
-        } else if (first_arg_return) {
-            ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
-            gen_param_types.append(gen_type->type_ref);
-            param_di_types.append(gen_type->di_type);
-            gen_return_type = g->builtin_types.entry_void;
-        } else {
-            gen_return_type = fn_type_id->return_type;
-        }
-        fn_type->data.fn.gen_return_type = gen_return_type;
-
-        if (prefix_arg_error_return_trace) {
-            ZigType *gen_type = get_ptr_to_stack_trace_type(g);
-            gen_param_types.append(gen_type->type_ref);
-            param_di_types.append(gen_type->di_type);
-        }
-        if (is_async) {
-            {
-                // async allocator param
-                ZigType *gen_type = fn_type_id->async_allocator_type;
-                gen_param_types.append(gen_type->type_ref);
-                param_di_types.append(gen_type->di_type);
-            }
-
-            {
-                // error code pointer
-                ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
-                gen_param_types.append(gen_type->type_ref);
-                param_di_types.append(gen_type->di_type);
-            }
-        }
-
-        fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
-        for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
-            FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
-            ZigType *type_entry = src_param_info->type;
-            FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
-
-            gen_param_info->src_index = i;
-            gen_param_info->gen_index = SIZE_MAX;
-
-            if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
-                return g->builtin_types.entry_invalid;
-
-            if (is_c_abi) {
-                if ((err = type_resolve(g, type_entry, ResolveStatusSizeKnown)))
-                    return g->builtin_types.entry_invalid;
-                continue;
-            }
-
-            if (type_has_bits(type_entry)) {
-                ZigType *gen_type;
-                if (handle_is_ptr(type_entry)) {
-                    gen_type = get_pointer_to_type(g, type_entry, true);
-                    gen_param_info->is_byval = true;
-                } else {
-                    gen_type = type_entry;
-                }
-                gen_param_info->gen_index = gen_param_types.length;
-                gen_param_info->type = gen_type;
-                gen_param_types.append(gen_type->type_ref);
-
-                param_di_types.append(gen_type->di_type);
-            }
-        }
 
-        if (is_c_abi) {
-            FnWalk fn_walk = {};
-            fn_walk.id = FnWalkIdTypes;
-            fn_walk.data.types.param_di_types = &param_di_types;
-            fn_walk.data.types.gen_param_types = &gen_param_types;
-            walk_function_params(g, fn_type, &fn_walk);
-        }
-
-        fn_type->data.fn.gen_param_count = gen_param_types.length;
-
-        for (size_t i = 0; i < gen_param_types.length; i += 1) {
-            assert(gen_param_types.items[i] != nullptr);
-        }
-        fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
-                gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
-        fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
-        fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
-        fn_type->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type,
-                LLVMStoreSizeOfType(g->target_data_ref, fn_type->type_ref),
-                LLVMABIAlignmentOfType(g->target_data_ref, fn_type->type_ref), "");
-    }
+    fn_type->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+    fn_type->abi_size = g->builtin_types.entry_usize->abi_size;
+    fn_type->abi_align = (fn_type_id->alignment == 0) ?
+        g->builtin_types.entry_usize->abi_align : fn_type_id->alignment;
 
     g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
 
@@ -1282,14 +925,6 @@ static ZigType *get_root_container_type(CodeGen *g, const char *full_name, Buf *
     entry->data.structure.decls_scope = create_decls_scope(g, nullptr, nullptr, entry, entry, bare_name);
     entry->data.structure.root_struct = root_struct;
     entry->data.structure.layout = ContainerLayoutAuto;
-    entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
-
-    size_t line = 0; // root therefore first line
-    unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
-
-    entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-        dwarf_kind, full_name,
-        ZigLLVMFileToScope(root_struct->di_file), root_struct->di_file, (unsigned)(line + 1));
 
     buf_init_from_str(&entry->name, full_name);
     return entry;
@@ -1316,16 +951,6 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
             break;
     }
 
-    size_t line = decl_node ? decl_node->line : 0;
-    unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
-
-    ZigType *import = get_scope_import(scope);
-    entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), full_name);
-    entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-        dwarf_kind, full_name,
-        ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-        import->data.structure.root_struct->di_file, (unsigned)(line + 1));
-
     buf_init_from_str(&entry->name, full_name);
 
     return entry;
@@ -1375,7 +1000,9 @@ ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
 
     fn_type->data.fn.fn_type_id = *fn_type_id;
     fn_type->data.fn.is_generic = true;
-    fn_type->zero_bits = true;
+    fn_type->abi_size = 0;
+    fn_type->size_in_bits = 0;
+    fn_type->abi_align = 0;
     return fn_type;
 }
 
@@ -1611,14 +1238,10 @@ ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) {
     ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
     buf_resize(&err_set_type->name, 0);
     buf_appendf(&err_set_type->name, "@typeOf(%s).ReturnType.ErrorSet", buf_ptr(&fn_entry->symbol_name));
-    err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
-    err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
     err_set_type->data.error_set.err_count = 0;
     err_set_type->data.error_set.errors = nullptr;
     err_set_type->data.error_set.infer_fn = fn_entry;
 
-    g->error_di_types.append(&err_set_type->di_type);
-
     return err_set_type;
 }
 
@@ -1858,10 +1481,10 @@ bool type_is_invalid(ZigType *type_entry) {
             return true;
         case ZigTypeIdStruct:
             return type_entry->data.structure.resolve_status == ResolveStatusInvalid;
+        case ZigTypeIdUnion:
+            return type_entry->data.unionation.resolve_status == ResolveStatusInvalid;
         case ZigTypeIdEnum:
             return type_entry->data.enumeration.is_invalid;
-        case ZigTypeIdUnion:
-            return type_entry->data.unionation.is_invalid;
         default:
             return false;
     }
@@ -1870,181 +1493,66 @@ bool type_is_invalid(ZigType *type_entry) {
 
 
 static Error resolve_enum_type(CodeGen *g, ZigType *enum_type) {
-    assert(enum_type->id == ZigTypeIdEnum);
+    return resolve_enum_zero_bits(g, enum_type);
+}
 
-    if (enum_type->data.enumeration.is_invalid)
-        return ErrorSemanticAnalyzeFail;
 
-    if (enum_type->data.enumeration.complete)
-        return ErrorNone;
+ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
+        ZigType *field_types[], size_t field_count)
+{
+    ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
 
-    Error err;
-    if ((err = resolve_enum_zero_bits(g, enum_type)))
-        return err;
+    buf_init_from_str(&struct_type->name, type_name);
 
-    AstNode *decl_node = enum_type->data.enumeration.decl_node;
+    struct_type->data.structure.src_field_count = field_count;
+    struct_type->data.structure.gen_field_count = 0;
+    struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
+    struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
+    struct_type->data.structure.fields_by_name.init(field_count);
 
-    if (enum_type->data.enumeration.embedded_in_current) {
-        if (!enum_type->data.enumeration.reported_infinite_err) {
-            enum_type->data.enumeration.is_invalid = true;
-            enum_type->data.enumeration.reported_infinite_err = true;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                    buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
+    size_t abi_align = 0;
+    for (size_t i = 0; i < field_count; i += 1) {
+        TypeStructField *field = &struct_type->data.structure.fields[i];
+        field->name = buf_create_from_str(field_names[i]);
+        field->type_entry = field_types[i];
+        field->src_index = i;
+
+        if (type_has_bits(field->type_entry)) {
+            assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));
+            if (field->type_entry->abi_align > abi_align) {
+                abi_align = field->type_entry->abi_align;
+            }
+            field->gen_index = struct_type->data.structure.gen_field_count;
+            struct_type->data.structure.gen_field_count += 1;
+        } else {
+            field->gen_index = SIZE_MAX;
         }
-        return ErrorSemanticAnalyzeFail;
+
+        auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
+        assert(prev_entry == nullptr);
     }
 
-    assert(!enum_type->data.enumeration.zero_bits_loop_flag);
-    assert(decl_node->type == NodeTypeContainerDecl);
-    assert(enum_type->di_type);
+    size_t next_offset = 0;
+    for (size_t i = 0; i < field_count; i += 1) {
+        TypeStructField *field = &struct_type->data.structure.fields[i];
+        field->offset = next_offset;
+        next_offset = next_field_offset(next_offset, abi_align,
+                field->type_entry->abi_size, field->type_entry->abi_align);
+    }
 
-    uint32_t field_count = enum_type->data.enumeration.src_field_count;
+    struct_type->abi_align = abi_align;
+    struct_type->abi_size = next_offset;
+    struct_type->size_in_bits = next_offset * 8;
 
-    assert(enum_type->data.enumeration.fields);
-    ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
+    return struct_type;
+}
 
-    Scope *scope = &enum_type->data.enumeration.decls_scope->base;
-    ZigType *import = get_scope_import(scope);
+static size_t get_store_size_in_bits(size_t size_in_bits) {
+    return (size_in_bits + 7) / 8;
+}
 
-    // set temporary flag
-    enum_type->data.enumeration.embedded_in_current = true;
-
-    for (uint32_t i = 0; i < field_count; i += 1) {
-        TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
-
-        // TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t
-        // http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html
-        di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name),
-                bigint_as_signed(&enum_field->value));
-    }
-
-    // unset temporary flag
-    enum_type->data.enumeration.embedded_in_current = false;
-    enum_type->data.enumeration.complete = true;
-
-    if (enum_type->data.enumeration.is_invalid)
-        return ErrorSemanticAnalyzeFail;
-
-    if (enum_type->zero_bits) {
-        enum_type->type_ref = LLVMVoidType();
-
-        uint64_t debug_size_in_bits = 0;
-        uint64_t debug_align_in_bits = 0;
-        ZigLLVMDIType **di_root_members = nullptr;
-        size_t debug_member_count = 0;
-        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-                buf_ptr(&enum_type->name),
-                import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-                debug_size_in_bits,
-                debug_align_in_bits,
-                0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
-
-        ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
-        enum_type->di_type = replacement_di_type;
-        return ErrorNone;
-    }
-
-    ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type;
-
-    // create debug type for tag
-    uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
-    uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
-    ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
-            ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name),
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            tag_debug_size_in_bits,
-            tag_debug_align_in_bits,
-            di_enumerators, field_count,
-            tag_int_type->di_type, "");
-
-    ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
-    enum_type->di_type = tag_di_type;
-    return ErrorNone;
-}
-
-
-ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
-        ZigType *field_types[], size_t field_count)
-{
-    ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
-
-    buf_init_from_str(&struct_type->name, type_name);
-
-    struct_type->data.structure.src_field_count = field_count;
-    struct_type->data.structure.gen_field_count = 0;
-    struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
-    struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
-    struct_type->data.structure.fields_by_name.init(field_count);
-
-    ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(field_count);
-    LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
-    for (size_t i = 0; i < field_count; i += 1) {
-        element_types[struct_type->data.structure.gen_field_count] = field_types[i]->type_ref;
-
-        TypeStructField *field = &struct_type->data.structure.fields[i];
-        field->name = buf_create_from_str(field_names[i]);
-        field->type_entry = field_types[i];
-        field->src_index = i;
-
-        if (type_has_bits(field->type_entry)) {
-            field->gen_index = struct_type->data.structure.gen_field_count;
-            struct_type->data.structure.gen_field_count += 1;
-        } else {
-            field->gen_index = SIZE_MAX;
-        }
-
-        auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
-        assert(prev_entry == nullptr);
-    }
-
-    struct_type->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), type_name);
-    LLVMStructSetBody(struct_type->type_ref, element_types, struct_type->data.structure.gen_field_count, false);
-
-    struct_type->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-        ZigLLVMTag_DW_structure_type(), type_name,
-        ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0);
-
-    for (size_t i = 0; i < field_count; i += 1) {
-        TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
-        if (type_struct_field->gen_index == SIZE_MAX) {
-            continue;
-        }
-        ZigType *field_type = type_struct_field->type_entry;
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
-        uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
-        uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, type_struct_field->gen_index);
-        di_element_types[type_struct_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
-                ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
-                nullptr, 0,
-                debug_size_in_bits,
-                debug_align_in_bits,
-                debug_offset_in_bits,
-                0, field_type->di_type);
-
-        assert(di_element_types[type_struct_field->gen_index]);
-    }
-
-    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
-    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
-    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-            ZigLLVMCompileUnitToScope(g->compile_unit),
-            type_name, nullptr, 0,
-            debug_size_in_bits,
-            debug_align_in_bits,
-            0,
-            nullptr, di_element_types, struct_type->data.structure.gen_field_count, 0, nullptr, "");
-
-    ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
-    struct_type->di_type = replacement_di_type;
-    struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, struct_type->type_ref);
-
-    return struct_type;
-}
-
-static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
-    assert(struct_type->id == ZigTypeIdStruct);
+static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
+    assert(struct_type->id == ZigTypeIdStruct);
 
     Error err;
 
@@ -2068,454 +1576,284 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
         return ErrorSemanticAnalyzeFail;
     }
 
-    struct_type->data.structure.resolve_loop_flag = true;
-
     assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0);
     assert(decl_node->type == NodeTypeContainerDecl);
 
     size_t field_count = struct_type->data.structure.src_field_count;
 
-    size_t gen_field_count = struct_type->data.structure.gen_field_count;
-    LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
+    bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
+    struct_type->data.structure.resolve_loop_flag = true;
 
-    Scope *scope = &struct_type->data.structure.decls_scope->base;
+    uint32_t *host_int_bytes = allocate<uint32_t>(struct_type->data.structure.gen_field_count);
 
-    size_t gen_field_index = 0;
-    bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
+    // Compute offsets for all the fields.
     size_t packed_bits_offset = 0;
+    size_t next_offset = 0;
     size_t first_packed_bits_offset_misalign = SIZE_MAX;
-    size_t debug_field_count = 0;
+    size_t gen_field_index = 0;
+    size_t size_in_bits = 0;
+    size_t abi_align = struct_type->abi_align;
 
     for (size_t i = 0; i < field_count; i += 1) {
         TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
         ZigType *field_type = type_struct_field->type_entry;
 
-        if ((err = ensure_complete_type(g, field_type))) {
+        if (!type_has_bits(field_type))
+            continue;
+
+        if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) {
             struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-            break;
+            return ErrorSemanticAnalyzeFail;
         }
 
-        if (struct_type->data.structure.layout == ContainerLayoutExtern) {
-            if (!type_allowed_in_extern(g, field_type)) {
-                AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
-                add_node_error(g, field_source_node,
-                        buf_sprintf("extern structs cannot contain fields of type '%s'",
-                            buf_ptr(&field_type->name)));
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                break;
-            }
+        if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) {
+            return ErrorSemanticAnalyzeFail;
         }
 
-        if (!type_has_bits(field_type))
-            continue;
-
         type_struct_field->gen_index = gen_field_index;
+        type_struct_field->offset = next_offset;
 
         if (packed) {
-            AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
-            if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                break;
-            }
-
             size_t field_size_in_bits = type_size_bits(g, field_type);
             size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
 
+            size_in_bits += field_size_in_bits;
+
             if (first_packed_bits_offset_misalign != SIZE_MAX) {
                 // this field is not byte-aligned; it is part of the previous field with a bit offset
                 type_struct_field->bit_offset_in_host = packed_bits_offset - first_packed_bits_offset_misalign;
 
                 size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
-                LLVMTypeRef int_type_ref = LLVMIntType((unsigned)(full_bit_count));
-                if (8 * LLVMStoreSizeOfType(g->target_data_ref, int_type_ref) == full_bit_count) {
+                if (get_store_size_in_bits(full_bit_count) == full_bit_count) {
                     // next field recovers store alignment
-                    element_types[gen_field_index] = int_type_ref;
+                    host_int_bytes[gen_field_index] = full_bit_count / 8;
                     gen_field_index += 1;
+                    // TODO: https://github.com/ziglang/zig/issues/1512
+                    next_offset = next_field_offset(next_offset, abi_align, full_bit_count / 8, 1);
+                    size_in_bits = next_offset * 8;
 
                     first_packed_bits_offset_misalign = SIZE_MAX;
                 }
-            } else if (8 * LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref) != field_size_in_bits) {
+            } else if (get_store_size_in_bits(field_type->size_in_bits) != field_size_in_bits) {
                 first_packed_bits_offset_misalign = packed_bits_offset;
                 type_struct_field->bit_offset_in_host = 0;
             } else {
                 // This is a byte-aligned field (both start and end) in a packed struct.
-                element_types[gen_field_index] = field_type->type_ref;
                 type_struct_field->bit_offset_in_host = 0;
                 gen_field_index += 1;
+                // TODO: https://github.com/ziglang/zig/issues/1512
+                next_offset = next_field_offset(next_offset, abi_align, field_type->size_in_bits / 8, 1);
+                size_in_bits = next_offset * 8;
             }
             packed_bits_offset = next_packed_bits_offset;
         } else {
-            element_types[gen_field_index] = field_type->type_ref;
-            assert(element_types[gen_field_index]);
-
             gen_field_index += 1;
+            next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, field_type->abi_align);
+            size_in_bits = next_offset * 8;
         }
-        debug_field_count += 1;
     }
     if (first_packed_bits_offset_misalign != SIZE_MAX) {
         size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
-        LLVMTypeRef int_type_ref = LLVMIntType((unsigned)full_bit_count);
-        size_t store_bit_count = 8 * LLVMStoreSizeOfType(g->target_data_ref, int_type_ref);
-        element_types[gen_field_index] = LLVMIntType((unsigned)store_bit_count);
+        size_t store_bit_count = get_store_size_in_bits(full_bit_count);
+        next_offset = next_field_offset(next_offset, abi_align, store_bit_count / 8, 1);
+        host_int_bytes[gen_field_index] = store_bit_count / 8;
         gen_field_index += 1;
     }
 
+    struct_type->abi_size = next_offset;
+    struct_type->size_in_bits = size_in_bits;
+    struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
+    struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index;
     struct_type->data.structure.resolve_loop_flag = false;
+    struct_type->data.structure.host_int_bytes = host_int_bytes;
 
-    if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
-        return ErrorSemanticAnalyzeFail;
+    return ErrorNone;
+}
 
-    struct_type->data.structure.resolve_status = ResolveStatusSizeKnown;
+static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
+    assert(union_type->id == ZigTypeIdUnion);
 
-    if (struct_type->zero_bits) {
-        struct_type->type_ref = LLVMVoidType();
+    Error err;
 
-        ZigType *import = get_scope_import(scope);
-        uint64_t debug_size_in_bits = 0;
-        uint64_t debug_align_in_bits = 0;
-        ZigLLVMDIType **di_element_types = nullptr;
-        size_t debug_field_count = 0;
-        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-                ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-                buf_ptr(&struct_type->name),
-                import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-                debug_size_in_bits,
-                debug_align_in_bits,
-                0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
-        ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
-        struct_type->di_type = replacement_di_type;
+    if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
+        return ErrorSemanticAnalyzeFail;
+    if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown)
         return ErrorNone;
+
+    if ((err = resolve_union_zero_bits(g, union_type)))
+        return err;
+
+    if (union_type->data.unionation.resolve_loop_flag) {
+        if (!union_type->data.unionation.reported_infinite_err) {
+            AstNode *decl_node = union_type->data.unionation.decl_node;
+            union_type->data.unionation.reported_infinite_err = true;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            ErrorMsg *msg = add_node_error(g, decl_node,
+                    buf_sprintf("union '%s' depends on its own alignment", buf_ptr(&union_type->name)));
+            emit_error_notes_for_ref_stack(g, msg);
+        }
+        return ErrorSemanticAnalyzeFail;
     }
-    assert(struct_type->di_type);
 
+    // set temporary flag
+    union_type->data.unionation.resolve_loop_flag = true;
 
-    // the count may have been adjusting from packing bit fields
-    gen_field_count = gen_field_index;
-    struct_type->data.structure.gen_field_count = (uint32_t)gen_field_count;
+    ZigType *most_aligned_union_member = nullptr;
+    uint32_t field_count = union_type->data.unionation.src_field_count;
 
-    LLVMStructSetBody(struct_type->type_ref, element_types, (unsigned)gen_field_count, packed);
+    for (uint32_t i = 0; i < field_count; i += 1) {
+        TypeUnionField *union_field = &union_type->data.unionation.fields[i];
+        ZigType *field_type = union_field->type_entry;
 
-    // if you hit this assert then probably this type or a related type didn't
-    // get ensure_complete_type called on it before using it with something that
-    // requires a complete type
-    assert(LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref) > 0);
+        if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        }
 
-    ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
+        if (type_is_invalid(union_type))
+            return ErrorSemanticAnalyzeFail;
 
-    ZigType *import = get_scope_import(scope);
-    size_t debug_field_index = 0;
-    for (size_t i = 0; i < field_count; i += 1) {
-        AstNode *field_node = decl_node->data.container_decl.fields.at(i);
-        TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
-        size_t gen_field_index = type_struct_field->gen_index;
-        if (gen_field_index == SIZE_MAX) {
+        if (!type_has_bits(field_type))
             continue;
+
+        if (most_aligned_union_member == nullptr ||
+            field_type->abi_align > most_aligned_union_member->abi_align)
+        {
+            most_aligned_union_member = field_type;
         }
+    }
 
-        ZigType *field_type = type_struct_field->type_entry;
+    // unset temporary flag
+    union_type->data.unionation.resolve_loop_flag = true;
+    union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown;
 
-        // if the field is a function, actually the debug info should be a pointer.
-        ZigLLVMDIType *field_di_type;
-        if (field_type->id == ZigTypeIdFn) {
-            ZigType *field_ptr_type = get_pointer_to_type(g, field_type, true);
-            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_ptr_type->type_ref);
-            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_ptr_type->type_ref);
-            field_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, field_type->di_type,
-                    debug_size_in_bits, debug_align_in_bits, buf_ptr(&field_ptr_type->name));
-        } else {
-            field_di_type = field_type->di_type;
+    ZigType *tag_type = union_type->data.unionation.tag_type;
+    if (tag_type != nullptr && type_has_bits(tag_type)) {
+        if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) {
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
         }
-
-        assert(field_type->type_ref);
-        assert(struct_type->type_ref);
-        assert(struct_type->data.structure.resolve_status == ResolveStatusSizeKnown);
-        uint64_t debug_size_in_bits;
-        uint64_t debug_align_in_bits;
-        uint64_t debug_offset_in_bits;
-        if (packed) {
-            debug_size_in_bits = type_size_bits(g, type_struct_field->type_entry);
-            debug_align_in_bits = 1;
-            debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref,
-                    (unsigned)gen_field_index) + type_struct_field->bit_offset_in_host;
+        if (most_aligned_union_member == nullptr) {
+            union_type->abi_align = tag_type->abi_align;
+            union_type->data.unionation.gen_tag_index = SIZE_MAX;
+            union_type->data.unionation.gen_union_index = SIZE_MAX;
+        } else if (tag_type->abi_align > most_aligned_union_member->abi_align) {
+            union_type->abi_align = tag_type->abi_align;
+            union_type->data.unionation.gen_tag_index = 0;
+            union_type->data.unionation.gen_union_index = 1;
         } else {
-            debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
-            debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);
-            debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref,
-                    (unsigned)gen_field_index);
+            union_type->abi_align = most_aligned_union_member->abi_align;
+            union_type->data.unionation.gen_union_index = 0;
+            union_type->data.unionation.gen_tag_index = 1;
         }
-        di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
-                ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
-                import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
-                debug_size_in_bits,
-                debug_align_in_bits,
-                debug_offset_in_bits,
-                0, field_di_type);
-        assert(di_element_types[debug_field_index]);
-        debug_field_index += 1;
+    } else {
+        assert(most_aligned_union_member != nullptr);
+        union_type->abi_align = most_aligned_union_member->abi_align;
+        union_type->data.unionation.gen_union_index = SIZE_MAX;
+        union_type->data.unionation.gen_tag_index = SIZE_MAX;
     }
 
-
-    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
-    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
-    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-            ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-            buf_ptr(&struct_type->name),
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            debug_size_in_bits,
-            debug_align_in_bits,
-            0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
-
-    ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
-    struct_type->di_type = replacement_di_type;
-
     return ErrorNone;
 }
 
 static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
     assert(union_type->id == ZigTypeIdUnion);
 
-    if (union_type->data.unionation.complete)
+    Error err;
+
+    if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
+        return ErrorSemanticAnalyzeFail;
+    if (union_type->data.unionation.resolve_status >= ResolveStatusSizeKnown)
         return ErrorNone;
 
-    Error err;
-    if ((err = resolve_union_zero_bits(g, union_type)))
+    if ((err = resolve_union_alignment(g, union_type)))
         return err;
 
     AstNode *decl_node = union_type->data.unionation.decl_node;
 
-    if (union_type->data.unionation.embedded_in_current) {
-        if (!union_type->data.unionation.reported_infinite_err) {
-            union_type->data.unionation.reported_infinite_err = true;
-            union_type->data.unionation.is_invalid = true;
-            ErrorMsg *msg = add_node_error(g, decl_node,
-                    buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
-            emit_error_notes_for_ref_stack(g, msg);
-        }
-        return ErrorSemanticAnalyzeFail;
-    }
 
-    assert(!union_type->data.unionation.zero_bits_loop_flag);
     assert(decl_node->type == NodeTypeContainerDecl);
-    assert(union_type->di_type);
 
     uint32_t field_count = union_type->data.unionation.src_field_count;
 
     assert(union_type->data.unionation.fields);
 
-    uint32_t gen_field_count = union_type->data.unionation.gen_field_count;
-    ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
-
-    ZigType *most_aligned_union_member = nullptr;
-    uint64_t size_of_most_aligned_member_in_bits = 0;
-    uint64_t biggest_align_in_bits = 0;
-    uint64_t biggest_size_in_bits = 0;
+    size_t union_abi_size = 0;
+    size_t union_size_in_bits = 0;
 
-    Scope *scope = &union_type->data.unionation.decls_scope->base;
-    ZigType *import = get_scope_import(scope);
+    if (union_type->data.unionation.resolve_loop_flag) {
+        if (!union_type->data.unionation.reported_infinite_err) {
+            union_type->data.unionation.reported_infinite_err = true;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            ErrorMsg *msg = add_node_error(g, decl_node,
+                    buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name)));
+            emit_error_notes_for_ref_stack(g, msg);
+        }
+        return ErrorSemanticAnalyzeFail;
+    }
 
     // set temporary flag
-    union_type->data.unionation.embedded_in_current = true;
-
+    union_type->data.unionation.resolve_loop_flag = true;
 
     for (uint32_t i = 0; i < field_count; i += 1) {
-        AstNode *field_node = decl_node->data.container_decl.fields.at(i);
         TypeUnionField *union_field = &union_type->data.unionation.fields[i];
         ZigType *field_type = union_field->type_entry;
 
-        if ((err = ensure_complete_type(g, field_type))) {
-            union_type->data.unionation.is_invalid = true;
-            continue;
+        if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) {
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
         }
 
+        if (type_is_invalid(union_type))
+            return ErrorSemanticAnalyzeFail;
+
         if (!type_has_bits(field_type))
             continue;
 
-        uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
-        uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
-
-        assert(store_size_in_bits > 0);
-        assert(abi_align_in_bits > 0);
-
-        union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
-                ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),
-                import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
-                store_size_in_bits,
-                abi_align_in_bits,
-                0,
-                0, field_type->di_type);
+        union_abi_size = max(union_abi_size, field_type->abi_size);
+        union_size_in_bits = max(union_size_in_bits, field_type->size_in_bits);
+    }
 
-        biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
+    // unset temporary flag
+    union_type->data.unionation.resolve_loop_flag = false;
+    union_type->data.unionation.resolve_status = ResolveStatusSizeKnown;
+    union_type->data.unionation.union_abi_size = union_abi_size;
 
-        if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
-            most_aligned_union_member = field_type;
-            biggest_align_in_bits = abi_align_in_bits;
-            size_of_most_aligned_member_in_bits = store_size_in_bits;
+    ZigType *tag_type = union_type->data.unionation.tag_type;
+    ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
+    if (tag_type != nullptr && type_has_bits(tag_type)) {
+        if ((err = type_resolve(g, tag_type, ResolveStatusSizeKnown))) {
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        }
+        if (most_aligned_union_member == nullptr) {
+            union_type->abi_size = tag_type->abi_size;
+            union_type->size_in_bits = tag_type->size_in_bits;
+        } else {
+            size_t field_sizes[2];
+            size_t field_aligns[2];
+            field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size;
+            field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align;
+            field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size;
+            field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->abi_align;
+            size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[0]);
+            union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], field_aligns[1]);
+            union_type->size_in_bits = union_type->abi_size * 8;
         }
+    } else {
+        union_type->abi_size = union_abi_size;
+        union_type->size_in_bits = union_size_in_bits;
     }
 
+    return ErrorNone;
+}
 
-    // unset temporary flag
-    union_type->data.unionation.embedded_in_current = false;
-    union_type->data.unionation.complete = true;
-    union_type->data.unionation.union_size_bytes = biggest_size_in_bits / 8;
-    union_type->data.unionation.most_aligned_union_member = most_aligned_union_member;
+static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
+    assert(enum_type->id == ZigTypeIdEnum);
 
-    if (union_type->data.unionation.is_invalid)
+    if (enum_type->data.enumeration.is_invalid)
         return ErrorSemanticAnalyzeFail;
 
-    if (union_type->zero_bits) {
-        union_type->type_ref = LLVMVoidType();
-
-        uint64_t debug_size_in_bits = 0;
-        uint64_t debug_align_in_bits = 0;
-        ZigLLVMDIType **di_root_members = nullptr;
-        size_t debug_member_count = 0;
-        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
-                ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-                buf_ptr(&union_type->name),
-                import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-                debug_size_in_bits,
-                debug_align_in_bits,
-                0, di_root_members, (int)debug_member_count, 0, "");
-
-        ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
-        union_type->di_type = replacement_di_type;
-        return ErrorNone;
-    }
-
-    uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
-
-    ZigType *tag_type = union_type->data.unionation.tag_type;
-    if (tag_type == nullptr || tag_type->zero_bits) {
-        assert(most_aligned_union_member != nullptr);
-
-        if (padding_in_bits > 0) {
-            ZigType *u8_type = get_int_type(g, false, 8);
-            ZigType *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
-            LLVMTypeRef union_element_types[] = {
-                most_aligned_union_member->type_ref,
-                padding_array->type_ref,
-            };
-            LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false);
-        } else {
-            LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false);
-        }
-        union_type->data.unionation.union_type_ref = union_type->type_ref;
-        union_type->data.unionation.gen_tag_index = SIZE_MAX;
-        union_type->data.unionation.gen_union_index = SIZE_MAX;
-
-        assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits);
-        assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits);
-
-        // create debug type for union
-        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
-            ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name),
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
-            gen_field_count, 0, "");
-
-        ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
-        union_type->di_type = replacement_di_type;
-        return ErrorNone;
-    }
-
-    LLVMTypeRef union_type_ref;
-    if (padding_in_bits > 0) {
-        ZigType *u8_type = get_int_type(g, false, 8);
-        ZigType *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
-        LLVMTypeRef union_element_types[] = {
-            most_aligned_union_member->type_ref,
-            padding_array->type_ref,
-        };
-        union_type_ref = LLVMStructType(union_element_types, 2, false);
-    } else if (most_aligned_union_member == nullptr) {
-        union_type->data.unionation.gen_tag_index = SIZE_MAX;
-        union_type->data.unionation.gen_union_index = SIZE_MAX;
-        union_type->type_ref = tag_type->type_ref;
-
-        ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type);
-        union_type->di_type = tag_type->di_type;
-        return ErrorNone;
-    } else {
-        union_type_ref = most_aligned_union_member->type_ref;
-    }
-    union_type->data.unionation.union_type_ref = union_type_ref;
-
-    assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
-    assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
-
-    // create llvm type for root struct
-    ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type;
-    uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
-
-    if (align_of_tag_in_bits >= biggest_align_in_bits) {
-        union_type->data.unionation.gen_tag_index = 0;
-        union_type->data.unionation.gen_union_index = 1;
-    } else {
-        union_type->data.unionation.gen_union_index = 0;
-        union_type->data.unionation.gen_tag_index = 1;
-    }
-
-    LLVMTypeRef root_struct_element_types[2];
-    root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type->type_ref;
-    root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
-    LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
-
-
-    // create debug type for union
-    ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
-            ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
-            gen_field_count, 0, "");
-
-    uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
-            union_type->data.unionation.gen_union_index);
-    uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
-            union_type->data.unionation.gen_tag_index);
-
-    ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
-            ZigLLVMTypeToScope(union_type->di_type), "payload",
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            biggest_size_in_bits,
-            biggest_align_in_bits,
-            union_offset_in_bits,
-            0, union_di_type);
-
-    uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
-    uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
-
-    ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
-            ZigLLVMTypeToScope(union_type->di_type), "tag",
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            tag_debug_size_in_bits,
-            tag_debug_align_in_bits,
-            tag_offset_in_bits,
-            0, tag_type->di_type);
-
-    ZigLLVMDIType *di_root_members[2];
-    di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
-    di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type;
-
-    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
-    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
-    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
-            ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
-            buf_ptr(&union_type->name),
-            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-            debug_size_in_bits,
-            debug_align_in_bits,
-            0, nullptr, di_root_members, 2, 0, nullptr, "");
-
-    ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
-    union_type->di_type = replacement_di_type;
-
-    return ErrorNone;
-}
-
-static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
-    assert(enum_type->id == ZigTypeIdEnum);
-
     if (enum_type->data.enumeration.zero_bits_known)
         return ErrorNone;
 
@@ -2531,7 +1869,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
 
     AstNode *decl_node = enum_type->data.enumeration.decl_node;
     assert(decl_node->type == NodeTypeContainerDecl);
-    assert(enum_type->di_type);
 
     assert(!enum_type->data.enumeration.fields);
     uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
@@ -2564,6 +1901,10 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
     }
 
+    enum_type->size_in_bits = tag_int_type->size_in_bits;
+    enum_type->abi_size = tag_int_type->abi_size;
+    enum_type->abi_align = tag_int_type->abi_align;
+
     // TODO: Are extern enums allowed to have an init_arg_expr?
     if (decl_node->data.container_decl.init_arg_expr != nullptr) {
         ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
@@ -2587,7 +1928,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         }
     }
     enum_type->data.enumeration.tag_int_type = tag_int_type;
-    enum_type->type_ref = tag_int_type->type_ref;
 
     for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
         AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
@@ -2671,7 +2011,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
     }
 
     enum_type->data.enumeration.zero_bits_loop_flag = false;
-    enum_type->zero_bits = !type_has_bits(tag_int_type);
     enum_type->data.enumeration.zero_bits_known = true;
 
     if (enum_type->data.enumeration.is_invalid)
@@ -2698,7 +2037,6 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
 
     AstNode *decl_node = struct_type->data.structure.decl_node;
     assert(decl_node->type == NodeTypeContainerDecl);
-    assert(struct_type->di_type);
 
     assert(!struct_type->data.structure.fields);
     size_t field_count = decl_node->data.container_decl.fields.length;
@@ -2767,7 +2105,10 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
 
     struct_type->data.structure.resolve_loop_flag = false;
     struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index;
-    struct_type->zero_bits = (gen_field_index == 0);
+    if (gen_field_index != 0) {
+        struct_type->abi_size = SIZE_MAX;
+        struct_type->size_in_bits = SIZE_MAX;
+    }
 
     if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
         return ErrorSemanticAnalyzeFail;
@@ -2803,52 +2144,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
 
     struct_type->data.structure.resolve_loop_flag = true;
     assert(decl_node->type == NodeTypeContainerDecl);
-    assert(struct_type->di_type);
 
+    size_t abi_align = 0;
     size_t field_count = struct_type->data.structure.src_field_count;
-    if (struct_type->data.structure.layout == ContainerLayoutPacked) {
-        struct_type->data.structure.abi_alignment = 1;
-        for (size_t i = 0; i < field_count; i += 1) {
-            TypeStructField *field = &struct_type->data.structure.fields[i];
-            if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) {
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                break;
-            }
-        }
-    } else for (size_t i = 0; i < field_count; i += 1) {
+    bool packed = struct_type->data.structure.layout == ContainerLayoutPacked;
+
+    for (size_t i = 0; i < field_count; i += 1) {
         TypeStructField *field = &struct_type->data.structure.fields[i];
-        uint32_t this_field_align;
-
-        // TODO If we have no type_entry for the field, we've already failed to
-        // compile the program correctly. This stage1 compiler needs a deeper
-        // reworking to make this correct, or we can ignore the problem
-        // and make sure it is fixed in stage2. This workaround is for when
-        // there is a false positive of a dependency loop, of alignment depending
-        // on itself. When this false positive happens we assume a pointer-aligned
-        // field, which is usually fine but could be incorrectly over-aligned or
-        // even under-aligned. See https://github.com/ziglang/zig/issues/1512
-        if (field->type_entry == nullptr) {
-            this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
-        } else {
-            if (type_is_invalid(field->type_entry)) {
-                struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                break;
-            }
+        ZigType *field_type = field->type_entry;
+        assert(field_type != nullptr);
 
-            if (!type_has_bits(field->type_entry))
-                continue;
+        if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
+            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        }
+
+        if (struct_type->data.structure.layout == ContainerLayoutExtern &&
+            !type_allowed_in_extern(g, field_type))
+        {
+            AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
+            add_node_error(g, field_source_node,
+                    buf_sprintf("extern structs cannot contain fields of type '%s'",
+                        buf_ptr(&field_type->name)));
+            struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
+        }
+
+        if (!type_has_bits(field_type))
+            continue;
 
-            if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
+        if (packed) {
+            AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
+            if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
                 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
-                break;
+                return ErrorSemanticAnalyzeFail;
+            }
+            // TODO: https://github.com/ziglang/zig/issues/1512
+            if (1 > abi_align) {
+                abi_align = 1;
+            }
+        } else {
+            // TODO: https://github.com/ziglang/zig/issues/1512
+            if (field_type->abi_align > abi_align) {
+                abi_align = field_type->abi_align;
             }
-
-            this_field_align = get_abi_alignment(g, field->type_entry);
-            assert(this_field_align != 0);
-        }
-        // alignment of structs is the alignment of the most-aligned field
-        if (this_field_align > struct_type->data.structure.abi_alignment) {
-            struct_type->data.structure.abi_alignment = this_field_align;
         }
     }
 
@@ -2859,6 +2198,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
     }
 
     struct_type->data.structure.resolve_status = ResolveStatusAlignmentKnown;
+    struct_type->abi_align = abi_align;
     return ErrorNone;
 }
 
@@ -2867,57 +2207,41 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
 
     Error err;
 
-    if (union_type->data.unionation.is_invalid)
+    if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
         return ErrorSemanticAnalyzeFail;
 
-    if (union_type->data.unionation.zero_bits_known)
+    if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown)
         return ErrorNone;
 
-    if (type_is_invalid(union_type))
-        return ErrorSemanticAnalyzeFail;
-
-    if (union_type->data.unionation.zero_bits_loop_flag) {
+    if (union_type->data.unionation.resolve_loop_flag) {
         // If we get here it's due to recursion. From this we conclude that the struct is
-        // not zero bits, and if abi_alignment == 0 we further conclude that the first field
-        // is a pointer to this very struct, or a function pointer with parameters that
-        // reference such a type.
-        union_type->data.unionation.zero_bits_known = true;
-        union_type->data.unionation.zero_bits_loop_flag = false;
-        if (union_type->data.unionation.abi_alignment == 0) {
-            if (union_type->data.unionation.layout == ContainerLayoutPacked) {
-                union_type->data.unionation.abi_alignment = 1;
-            } else {
-                union_type->data.unionation.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
-                        LLVMPointerType(LLVMInt8Type(), 0));
-            }
-        }
+        // not zero bits.
+        // TODO actually it could still be zero bits. Here we should continue analyzing
+        // the union from the next field index.
+        union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown;
+        union_type->data.unionation.resolve_loop_flag = false;
+        union_type->abi_size = SIZE_MAX;
+        union_type->size_in_bits = SIZE_MAX;
         return ErrorNone;
     }
 
-    union_type->data.unionation.zero_bits_loop_flag = true;
+    union_type->data.unionation.resolve_loop_flag = true;
 
     AstNode *decl_node = union_type->data.unionation.decl_node;
     assert(decl_node->type == NodeTypeContainerDecl);
-    assert(union_type->di_type);
 
-    assert(!union_type->data.unionation.fields);
+    assert(union_type->data.unionation.fields == nullptr);
     uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
     if (field_count == 0) {
         add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
-
         union_type->data.unionation.src_field_count = field_count;
-        union_type->data.unionation.fields = nullptr;
-        union_type->data.unionation.is_invalid = true;
-        union_type->data.unionation.zero_bits_loop_flag = false;
-        union_type->data.unionation.zero_bits_known = true;
+        union_type->data.unionation.resolve_status = ResolveStatusInvalid;
         return ErrorSemanticAnalyzeFail;
     }
     union_type->data.unionation.src_field_count = field_count;
     union_type->data.unionation.fields = allocate<TypeUnionField>(field_count);
     union_type->data.unionation.fields_by_name.init(field_count);
 
-    uint32_t biggest_align_bytes = 0;
-
     Scope *scope = &union_type->data.unionation.decls_scope->base;
 
     HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
@@ -2931,7 +2255,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
     bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
     bool *covered_enum_fields;
     ZigLLVMDIEnumerator **di_enumerators;
-    uint32_t abi_alignment_so_far;
     if (create_enum_type) {
         occupied_tag_values.init(field_count);
 
@@ -2941,13 +2264,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
         if (enum_type_node != nullptr) {
             tag_int_type = analyze_type_expr(g, scope, enum_type_node);
             if (type_is_invalid(tag_int_type)) {
-                union_type->data.unionation.is_invalid = true;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
                 return ErrorSemanticAnalyzeFail;
             }
             if (tag_int_type->id != ZigTypeIdInt) {
                 add_node_error(g, enum_type_node,
                     buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
-                union_type->data.unionation.is_invalid = true;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
                 return ErrorSemanticAnalyzeFail;
             }
         } else if (auto_layout && field_count == 1) {
@@ -2955,13 +2278,15 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
         } else {
             tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
         }
-        abi_alignment_so_far = get_abi_alignment(g, tag_int_type);
 
         tag_type = new_type_table_entry(ZigTypeIdEnum);
         buf_resize(&tag_type->name, 0);
         buf_appendf(&tag_type->name, "@TagType(%s)", buf_ptr(&union_type->name));
-        tag_type->type_ref = tag_int_type->type_ref;
-        tag_type->zero_bits = tag_int_type->zero_bits;
+        tag_type->llvm_type = tag_int_type->llvm_type;
+        tag_type->llvm_di_type = tag_int_type->llvm_di_type;
+        tag_type->abi_size = tag_int_type->abi_size;
+        tag_type->abi_align = tag_int_type->abi_align;
+        tag_type->size_in_bits = tag_int_type->size_in_bits;
 
         tag_type->data.enumeration.tag_int_type = tag_int_type;
         tag_type->data.enumeration.zero_bits_known = true;
@@ -2975,11 +2300,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
     } else if (enum_type_node != nullptr) {
         ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node);
         if (type_is_invalid(enum_type)) {
-            union_type->data.unionation.is_invalid = true;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
             return ErrorSemanticAnalyzeFail;
         }
         if (enum_type->id != ZigTypeIdEnum) {
-            union_type->data.unionation.is_invalid = true;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
             add_node_error(g, enum_type_node,
                 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
             return ErrorSemanticAnalyzeFail;
@@ -2989,11 +2314,9 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
             return err;
         }
         tag_type = enum_type;
-        abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
         covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
     } else {
         tag_type = nullptr;
-        abi_alignment_so_far = 0;
     }
     union_type->data.unionation.tag_type = tag_type;
 
@@ -3010,8 +2333,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
             ErrorMsg *msg = add_node_error(g, field_node,
                 buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
             add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
-            union_type->data.unionation.is_invalid = true;
-            continue;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
         }
 
         ZigType *field_type;
@@ -3020,29 +2343,31 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
                 field_type = g->builtin_types.entry_void;
             } else {
                 add_node_error(g, field_node, buf_sprintf("union field missing type"));
-                union_type->data.unionation.is_invalid = true;
-                continue;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                return ErrorSemanticAnalyzeFail;
             }
         } else {
             field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
             if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) {
-                union_type->data.unionation.is_invalid = true;
-                continue;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                return ErrorSemanticAnalyzeFail;
             }
+            if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
+                return ErrorSemanticAnalyzeFail;
         }
         union_field->type_entry = field_type;
 
         if (field_type->id == ZigTypeIdOpaque) {
             add_node_error(g, field_node->data.struct_field.type,
                 buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions"));
-            union_type->data.unionation.is_invalid = true;
-            continue;
+            union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+            return ErrorSemanticAnalyzeFail;
         }
 
         switch (type_requires_comptime(g, field_type)) {
             case ReqCompTimeInvalid:
-                union_type->data.unionation.is_invalid = true;
-                continue;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                return ErrorSemanticAnalyzeFail;
             case ReqCompTimeYes:
                 union_type->data.unionation.requires_comptime = true;
                 break;
@@ -3074,8 +2399,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
                 ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type;
                 ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
                 if (type_is_invalid(result->type)) {
-                    union_type->data.unionation.is_invalid = true;
-                    continue;
+                    union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                    return ErrorSemanticAnalyzeFail;
                 }
                 assert(result->special != ConstValSpecialRuntime);
                 assert(result->type->id == ZigTypeIdInt);
@@ -3090,8 +2415,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
                             buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
                     add_error_note(g, msg, entry->value,
                             buf_sprintf("other occurrence here"));
-                    union_type->data.unionation.is_invalid = true;
-                    continue;
+                    union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                    return ErrorSemanticAnalyzeFail;
                 }
             }
         } else if (enum_type_node != nullptr) {
@@ -3101,8 +2426,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
                     buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
                 add_error_note(g, msg, tag_type->data.enumeration.decl_node,
                         buf_sprintf("enum declared here"));
-                union_type->data.unionation.is_invalid = true;
-                continue;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                return ErrorSemanticAnalyzeFail;
             }
             covered_enum_fields[union_field->enum_field->decl_index] = true;
         } else {
@@ -3118,21 +2443,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
 
         union_field->gen_index = gen_field_index;
         gen_field_index += 1;
-
-        uint32_t field_align_bytes = get_abi_alignment(g, field_type);
-        if (field_align_bytes > biggest_align_bytes) {
-            biggest_align_bytes = field_align_bytes;
-            if (biggest_align_bytes > abi_alignment_so_far) {
-                abi_alignment_so_far = biggest_align_bytes;
-            }
-        }
     }
 
-    union_type->data.unionation.abi_alignment = abi_alignment_so_far;
-
-    if (union_type->data.unionation.is_invalid)
-        return ErrorSemanticAnalyzeFail;
-
     bool src_have_tag = decl_node->data.container_decl.auto_enum ||
         decl_node->data.container_decl.init_arg_expr != nullptr;
 
@@ -3152,7 +2464,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
             decl_node->data.container_decl.init_arg_expr : decl_node;
         add_node_error(g, source_node,
             buf_sprintf("%s union does not support enum tag type", qual_str));
-        union_type->data.unionation.is_invalid = true;
+        union_type->data.unionation.resolve_status = ResolveStatusInvalid;
         return ErrorSemanticAnalyzeFail;
     }
 
@@ -3194,33 +2506,24 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
                     buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
                 add_error_note(g, msg, field_node,
                         buf_sprintf("declared here"));
-                union_type->data.unionation.is_invalid = true;
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
             }
         }
     }
 
-    if (create_enum_type) {
-        ZigType *import = get_scope_import(scope);
-        uint64_t tag_debug_size_in_bits = tag_type->zero_bits ? 0 :
-            8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
-        uint64_t tag_debug_align_in_bits = tag_type->zero_bits ? 0 :
-            8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
-        // TODO get a more accurate debug scope
-        ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
-                ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&tag_type->name),
-                import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
-                tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
-                tag_type->di_type, "");
-        tag_type->di_type = tag_di_type;
-    }
-
-    union_type->data.unionation.zero_bits_loop_flag = false;
-    union_type->data.unionation.gen_field_count = gen_field_index;
-    union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
-    union_type->data.unionation.zero_bits_known = true;
-
-    if (union_type->data.unionation.is_invalid)
+    if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) {
         return ErrorSemanticAnalyzeFail;
+    }
+
+    union_type->data.unionation.resolve_loop_flag = false;
+
+    union_type->data.unionation.gen_field_count = gen_field_index;
+    bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag);
+    if (!zero_bits) {
+        union_type->abi_size = SIZE_MAX;
+        union_type->size_in_bits = SIZE_MAX;
+    }
+    union_type->data.unionation.resolve_status = zero_bits ? ResolveStatusSizeKnown : ResolveStatusZeroBitsKnown;
 
     return ErrorNone;
 }
@@ -4007,7 +3310,7 @@ TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name) {
 
 TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name) {
     assert(type_entry->id == ZigTypeIdUnion);
-    assert(type_entry->data.unionation.zero_bits_known);
+    assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
     if (type_entry->data.unionation.src_field_count == 0)
         return nullptr;
     auto entry = type_entry->data.unionation.fields_by_name.maybe_get(name);
@@ -4018,7 +3321,7 @@ TypeUnionField *find_union_type_field(ZigType *type_entry, Buf *name) {
 
 TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) {
     assert(type_entry->id == ZigTypeIdUnion);
-    assert(type_entry->data.unionation.zero_bits_known);
+    assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
     for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
         TypeUnionField *field = &type_entry->data.unionation.fields[i];
         if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) {
@@ -4626,18 +3929,26 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
     }
 
     ZigType *entry = new_type_table_entry(ZigTypeIdVector);
-    entry->zero_bits = (len == 0) || !type_has_bits(elem_type);
-    entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len);
+    if ((len != 0) && type_has_bits(elem_type)) {
+        // Vectors can only be ints, floats, or pointers. ints and floats have trivially resolvable
+        // llvm type refs. pointers we will use usize instead.
+        LLVMTypeRef example_vector_llvm_type;
+        if (elem_type->id == ZigTypeIdPointer) {
+            example_vector_llvm_type = LLVMVectorType(g->builtin_types.entry_usize->llvm_type, len);
+        } else {
+            example_vector_llvm_type = LLVMVectorType(elem_type->llvm_type, len);
+        }
+        assert(example_vector_llvm_type != nullptr);
+        entry->size_in_bits = elem_type->size_in_bits * len;
+        entry->abi_size = LLVMABISizeOfType(g->target_data_ref, example_vector_llvm_type);
+        entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, example_vector_llvm_type);
+    }
     entry->data.vector.len = len;
     entry->data.vector.elem_type = elem_type;
 
     buf_resize(&entry->name, 0);
     buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name));
 
-    entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder,
-            len * type_size_bits(g, elem_type),
-            LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type, len);
-
     g->type_table.put(type_id, entry);
     return entry;
 }
@@ -4677,6 +3988,7 @@ bool handle_is_ptr(ZigType *type_entry) {
              return false;
         case ZigTypeIdArray:
         case ZigTypeIdStruct:
+        case ZigTypeIdUnion:
              return type_has_bits(type_entry);
         case ZigTypeIdErrorUnion:
              return type_has_bits(type_entry->data.error_union.payload_type);
@@ -4684,13 +3996,6 @@ bool handle_is_ptr(ZigType *type_entry) {
              return type_has_bits(type_entry->data.maybe.child_type) &&
                     !type_is_nonnull_ptr(type_entry->data.maybe.child_type) &&
                     type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
-        case ZigTypeIdUnion:
-             assert(type_entry->data.unionation.zero_bits_known);
-             if (type_entry->data.unionation.gen_field_count == 0)
-                 return false;
-             if (!type_has_bits(type_entry))
-                 return false;
-             return true;
 
     }
     zig_unreachable();
@@ -5165,10 +4470,10 @@ bool fn_eval_eql(Scope *a, Scope *b) {
 
 // Whether the type has bits at runtime.
 bool type_has_bits(ZigType *type_entry) {
-    assert(type_entry);
+    assert(type_entry != nullptr);
     assert(!type_is_invalid(type_entry));
     assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
-    return !type_entry->zero_bits;
+    return type_entry->abi_size != 0;
 }
 
 // Whether you can infer the value based solely on the type.
@@ -5629,7 +4934,7 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
             } else if (ty->id == ZigTypeIdEnum) {
                 return resolve_enum_zero_bits(g, ty);
             } else if (ty->id == ZigTypeIdUnion) {
-                return resolve_union_zero_bits(g, ty);
+                return resolve_union_alignment(g, ty);
             }
             return ErrorNone;
         case ResolveStatusSizeKnown:
@@ -6192,31 +5497,18 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
 ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
     assert(size_in_bits <= 65535);
     ZigType *entry = new_type_table_entry(ZigTypeIdInt);
-    entry->type_ref = (size_in_bits == 0) ? LLVMVoidType() : LLVMIntType(size_in_bits);
-    entry->zero_bits = (size_in_bits == 0);
+
+    entry->size_in_bits = size_in_bits;
+    if (size_in_bits != 0) {
+        entry->llvm_type = LLVMIntType(size_in_bits);
+        entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
+        entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
+    }
 
     const char u_or_i = is_signed ? 'i' : 'u';
     buf_resize(&entry->name, 0);
     buf_appendf(&entry->name, "%c%" PRIu32, u_or_i, size_in_bits);
 
-    unsigned dwarf_tag;
-    if (is_signed) {
-        if (size_in_bits == 8) {
-            dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char();
-        } else {
-            dwarf_tag = ZigLLVMEncoding_DW_ATE_signed();
-        }
-    } else {
-        if (size_in_bits == 8) {
-            dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char();
-        } else {
-            dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned();
-        }
-    }
-
-    uint64_t debug_size_in_bits = (size_in_bits == 0) ?
-        0 : (8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref));
-    entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), debug_size_in_bits, dwarf_tag);
     entry->data.integral.is_signed = is_signed;
     entry->data.integral.bit_count = size_in_bits;
     return entry;
@@ -6620,26 +5912,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
     return link_lib;
 }
 
-uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry) {
-    assert(type_is_resolved(type_entry, ResolveStatusAlignmentKnown));
-    if (type_entry->zero_bits) return 0;
-
-    // We need to make this function work without requiring ensure_complete_type
-    // so that we can have structs with fields that are pointers to their own type.
-    if (type_entry->id == ZigTypeIdStruct) {
-        assert(type_entry->data.structure.abi_alignment != 0);
-        return type_entry->data.structure.abi_alignment;
-    } else if (type_entry->id == ZigTypeIdUnion) {
-        assert(type_entry->data.unionation.abi_alignment != 0);
-        return type_entry->data.unionation.abi_alignment;
-    } else if (type_entry->id == ZigTypeIdOpaque) {
-        return 1;
-    } else {
-        uint32_t llvm_alignment = LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
-        return llvm_alignment;
-    }
-}
-
 ZigType *get_align_amt_type(CodeGen *g) {
     if (g->align_amt_type == nullptr) {
         // according to LLVM the maximum alignment is 1 << 29.
@@ -6841,11 +6113,8 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
 
 uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field) {
     assert(struct_type->id == ZigTypeIdStruct);
-    if (struct_type->data.structure.layout != ContainerLayoutPacked) {
-        return 0;
-    }
-    LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(struct_type->type_ref, field->gen_index);
-    return LLVMStoreSizeOfType(g->target_data_ref, field_type);
+    assert(type_is_resolved(struct_type, ResolveStatusSizeKnown));
+    return struct_type->data.structure.host_int_bytes[field->gen_index];
 }
 
 Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
@@ -6911,3 +6180,822 @@ Buf *type_bare_name(ZigType *type_entry) {
 Buf *type_h_name(ZigType *t) {
     return type_bare_name(t);
 }
+
+static void resolve_llvm_types_slice(CodeGen *g, ZigType *type) {
+    ZigType *ptr_type = type->data.structure.fields[slice_ptr_index].type_entry;
+    ZigType *child_type = ptr_type->data.pointer.child_type;
+
+    if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
+        ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
+    {
+        ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
+                PtrLenUnknown, 0, 0, 0, false);
+        ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
+
+        type->llvm_type = get_llvm_type(g, peer_slice_type);
+        type->llvm_di_type = get_llvm_di_type(g, peer_slice_type);
+    }
+
+    // If the child type is []const T then we need to make sure the type ref
+    // and debug info is the same as if the child type were []T.
+    if (is_slice(child_type)) {
+        ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
+        assert(child_ptr_type->id == ZigTypeIdPointer);
+        if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
+            child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
+        {
+            ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
+            ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
+                    PtrLenUnknown, 0, 0, 0, false);
+            ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
+            ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
+                    PtrLenUnknown, 0, 0, 0, false);
+            ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
+
+            type->llvm_type = get_llvm_type(g, peer_slice_type);
+            type->llvm_di_type = get_llvm_di_type(g, peer_slice_type);
+        }
+    }
+
+    if (type->llvm_type != nullptr)
+        return;
+
+    ZigType *usize_type = g->builtin_types.entry_usize;
+    LLVMTypeRef usize_llvm_type = get_llvm_type(g, usize_type);
+    ZigLLVMDIType *usize_llvm_di_type = get_llvm_di_type(g, usize_type);
+
+    type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name));
+
+    ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
+    ZigLLVMDIFile *di_file = nullptr;
+    unsigned line = 0;
+    type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+        ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name),
+        compile_unit_scope, di_file, line);
+
+    if (!type_has_bits(child_type)) {
+        LLVMTypeRef element_types[] = {
+            usize_llvm_type,
+        };
+        LLVMStructSetBody(type->llvm_type, element_types, 1, false);
+
+        uint64_t len_debug_size_in_bits = usize_type->size_in_bits;
+        uint64_t len_debug_align_in_bits = 8*usize_type->abi_align;
+        uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
+
+        uint64_t debug_size_in_bits = type->size_in_bits;
+        uint64_t debug_align_in_bits = 8*type->abi_align;
+
+        ZigLLVMDIType *di_element_types[] = {
+            ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                    "len", di_file, line,
+                    len_debug_size_in_bits,
+                    len_debug_align_in_bits,
+                    len_offset_in_bits,
+                    0, usize_llvm_di_type),
+        };
+        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+                compile_unit_scope,
+                buf_ptr(&type->name),
+                di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+                nullptr, di_element_types, 1, 0, nullptr, "");
+
+        ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
+        type->llvm_di_type = replacement_di_type;
+        return;
+    }
+
+    LLVMTypeRef element_types[2];
+    element_types[slice_ptr_index] = get_llvm_type(g, ptr_type);
+    element_types[slice_len_index] = get_llvm_type(g, g->builtin_types.entry_usize);
+    LLVMStructSetBody(type->llvm_type, element_types, 2, false);
+
+    uint64_t ptr_debug_size_in_bits = ptr_type->size_in_bits;
+    uint64_t ptr_debug_align_in_bits = 8*ptr_type->abi_align;
+    uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
+
+    uint64_t len_debug_size_in_bits = usize_type->size_in_bits;
+    uint64_t len_debug_align_in_bits = 8*usize_type->abi_align;
+    uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1);
+
+    uint64_t debug_size_in_bits = type->size_in_bits;
+    uint64_t debug_align_in_bits = 8*type->abi_align;
+
+    ZigLLVMDIType *di_element_types[] = {
+        ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                "ptr", di_file, line,
+                ptr_debug_size_in_bits,
+                ptr_debug_align_in_bits,
+                ptr_offset_in_bits,
+                0, get_llvm_di_type(g, ptr_type)),
+        ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                "len", di_file, line,
+                len_debug_size_in_bits,
+                len_debug_align_in_bits,
+                len_offset_in_bits,
+                0, usize_llvm_di_type),
+    };
+    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+            compile_unit_scope,
+            buf_ptr(&type->name),
+            di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+            nullptr, di_element_types, 2, 0, nullptr, "");
+
+    ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
+    type->llvm_di_type = replacement_di_type;
+}
+
+static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type) {
+    assert(struct_type->id == ZigTypeIdStruct);
+    assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);
+    assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);
+    assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0);
+
+    AstNode *decl_node = struct_type->data.structure.decl_node;
+    assert(decl_node->type == NodeTypeContainerDecl);
+
+    size_t field_count = struct_type->data.structure.src_field_count;
+    size_t gen_field_count = struct_type->data.structure.gen_field_count;
+    LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
+
+    Scope *scope = &struct_type->data.structure.decls_scope->base;
+
+    size_t gen_field_index = 0;
+    bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
+    size_t packed_bits_offset = 0;
+    size_t first_packed_bits_offset_misalign = SIZE_MAX;
+    size_t debug_field_count = 0;
+
+    for (size_t i = 0; i < field_count; i += 1) {
+        TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+        ZigType *field_type = type_struct_field->type_entry;
+
+        if (!type_has_bits(field_type))
+            continue;
+
+        if (packed) {
+            size_t field_size_in_bits = type_size_bits(g, field_type);
+            size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
+
+            if (first_packed_bits_offset_misalign != SIZE_MAX) {
+                // this field is not byte-aligned; it is part of the previous field with a bit offset
+
+                size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
+                if (get_store_size_in_bits(full_bit_count) == full_bit_count) {
+                    // next field recovers store alignment
+                    element_types[gen_field_index] = LLVMIntType((unsigned)(full_bit_count));
+                    gen_field_index += 1;
+
+                    first_packed_bits_offset_misalign = SIZE_MAX;
+                }
+            } else if (get_store_size_in_bits(field_type->size_in_bits) != field_size_in_bits) {
+                first_packed_bits_offset_misalign = packed_bits_offset;
+            } else {
+                // This is a byte-aligned field (both start and end) in a packed struct.
+                element_types[gen_field_index] = get_llvm_type(g, field_type);
+                gen_field_index += 1;
+            }
+            packed_bits_offset = next_packed_bits_offset;
+        } else {
+            element_types[gen_field_index] = get_llvm_type(g, field_type);
+
+            gen_field_index += 1;
+        }
+        debug_field_count += 1;
+    }
+    if (first_packed_bits_offset_misalign != SIZE_MAX) {
+        size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
+        size_t store_bit_count = get_store_size_in_bits(full_bit_count);
+        element_types[gen_field_index] = LLVMIntType((unsigned)store_bit_count);
+        gen_field_index += 1;
+    }
+
+    struct_type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&struct_type->name));
+    LLVMStructSetBody(struct_type->llvm_type, element_types, (unsigned)gen_field_count, packed);
+
+    ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
+
+    ZigType *import = get_scope_import(scope);
+    size_t debug_field_index = 0;
+    for (size_t i = 0; i < field_count; i += 1) {
+        AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+        TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+        size_t gen_field_index = type_struct_field->gen_index;
+        if (gen_field_index == SIZE_MAX) {
+            continue;
+        }
+
+        ZigType *field_type = type_struct_field->type_entry;
+
+        // if the field is a function, actually the debug info should be a pointer.
+        ZigLLVMDIType *field_di_type;
+        if (field_type->id == ZigTypeIdFn) {
+            ZigType *field_ptr_type = get_pointer_to_type(g, field_type, true);
+            uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type));
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, field_ptr_type));
+            field_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, field_type),
+                    debug_size_in_bits, debug_align_in_bits, buf_ptr(&field_ptr_type->name));
+        } else {
+            field_di_type = get_llvm_di_type(g, field_type);
+        }
+
+        uint64_t debug_size_in_bits;
+        uint64_t debug_align_in_bits;
+        uint64_t debug_offset_in_bits;
+        if (packed) {
+            debug_size_in_bits = type_struct_field->type_entry->size_in_bits;
+            debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;
+            debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;
+        } else {
+            debug_size_in_bits = get_store_size_in_bits(field_type->size_in_bits);
+            debug_align_in_bits = 8 * field_type->abi_align;
+            debug_offset_in_bits = 8 * type_struct_field->offset;
+        }
+        di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
+                ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(type_struct_field->name),
+                import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
+                debug_size_in_bits,
+                debug_align_in_bits,
+                debug_offset_in_bits,
+                0, field_di_type);
+        assert(di_element_types[debug_field_index]);
+        debug_field_index += 1;
+    }
+
+    uint64_t debug_size_in_bits = get_store_size_in_bits(struct_type->size_in_bits);
+    uint64_t debug_align_in_bits = 8*struct_type->abi_align;
+    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+            ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
+            buf_ptr(&struct_type->name),
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            debug_size_in_bits,
+            debug_align_in_bits,
+            0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, "");
+
+    ZigLLVMReplaceTemporary(g->dbuilder, struct_type->llvm_di_type, replacement_di_type);
+    struct_type->llvm_di_type = replacement_di_type;
+}
+
+static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) {
+    assert(!enum_type->data.enumeration.is_invalid);
+    assert(enum_type->data.enumeration.complete);
+
+    uint32_t field_count = enum_type->data.enumeration.src_field_count;
+
+    assert(enum_type->data.enumeration.fields);
+    ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
+
+    Scope *scope = &enum_type->data.enumeration.decls_scope->base;
+    ZigType *import = get_scope_import(scope);
+
+    for (uint32_t i = 0; i < field_count; i += 1) {
+        TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
+
+        // TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t
+        // http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html
+        di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name),
+                bigint_as_signed(&enum_field->value));
+    }
+
+    ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type;
+
+    // create debug type for tag
+    AstNode *decl_node = enum_type->data.enumeration.decl_node;
+    uint64_t tag_debug_size_in_bits = tag_int_type->size_in_bits;
+    uint64_t tag_debug_align_in_bits = 8*tag_int_type->abi_align;
+    ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+            ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name),
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            tag_debug_size_in_bits,
+            tag_debug_align_in_bits,
+            di_enumerators, field_count,
+            get_llvm_di_type(g, tag_int_type), "");
+
+    enum_type->llvm_di_type = tag_di_type;
+}
+
+static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type) {
+    ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
+    ZigType *tag_type = union_type->data.unionation.tag_type;
+    if (tag_type == nullptr || !type_has_bits(tag_type)) {
+        assert(most_aligned_union_member != nullptr);
+        assert(union_type->data.unionation.union_abi_size >= most_aligned_union_member->abi_size);
+        union_type->llvm_type = get_llvm_type(g, most_aligned_union_member);
+        union_type->llvm_di_type = get_llvm_di_type(g, most_aligned_union_member);
+        return;
+    }
+    if (most_aligned_union_member == nullptr) {
+        union_type->llvm_type = get_llvm_type(g, tag_type);
+        union_type->llvm_di_type = get_llvm_di_type(g, tag_type);
+        return;
+    }
+
+    Scope *scope = &union_type->data.unionation.decls_scope->base;
+    ZigType *import = get_scope_import(scope);
+    AstNode *decl_node = union_type->data.unionation.decl_node;
+    size_t line = decl_node ? decl_node->line : 0;
+    unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
+    union_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+        dwarf_kind, buf_ptr(&union_type->name),
+        ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
+        import->data.structure.root_struct->di_file, (unsigned)(line + 1));
+
+    uint32_t gen_field_count = union_type->data.unionation.gen_field_count;
+    ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
+    uint32_t field_count = union_type->data.unionation.src_field_count;
+    for (uint32_t i = 0; i < field_count; i += 1) {
+        TypeUnionField *union_field = &union_type->data.unionation.fields[i];
+        if (!type_has_bits(union_field->type_entry))
+            continue;
+
+        uint64_t store_size_in_bits = union_field->type_entry->size_in_bits;
+        uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align;
+        AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+        union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
+                ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name),
+                import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
+                store_size_in_bits,
+                abi_align_in_bits,
+                0,
+                0, get_llvm_di_type(g, union_field->type_entry));
+
+    }
+    union_type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&union_type->name));
+
+    LLVMTypeRef union_type_ref;
+    size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->abi_size;
+    if (padding_bytes == 0) {
+        union_type_ref = get_llvm_type(g, most_aligned_union_member);
+    } else {
+        ZigType *u8_type = get_int_type(g, false, 8);
+        ZigType *padding_array = get_array_type(g, u8_type, padding_bytes);
+        LLVMTypeRef union_element_types[] = {
+            get_llvm_type(g, most_aligned_union_member),
+            get_llvm_type(g, padding_array),
+        };
+        union_type_ref = LLVMStructType(union_element_types, 2, false);
+    }
+    union_type->data.unionation.union_llvm_type = union_type_ref;
+
+    LLVMTypeRef root_struct_element_types[2];
+    root_struct_element_types[union_type->data.unionation.gen_tag_index] = get_llvm_type(g, tag_type);
+    root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
+    LLVMStructSetBody(union_type->llvm_type, root_struct_element_types, 2, false);
+
+    // create debug type for union
+    ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
+            ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion",
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            most_aligned_union_member->size_in_bits, 8*most_aligned_union_member->abi_align,
+            0, union_inner_di_types, gen_field_count, 0, "");
+
+    uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type,
+            union_type->data.unionation.gen_union_index);
+    uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type,
+            union_type->data.unionation.gen_tag_index);
+
+    ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+            ZigLLVMTypeToScope(union_type->llvm_di_type), "payload",
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            most_aligned_union_member->size_in_bits,
+            8*most_aligned_union_member->abi_align,
+            union_offset_in_bits,
+            0, union_di_type);
+
+    uint64_t tag_debug_size_in_bits = tag_type->size_in_bits;
+    uint64_t tag_debug_align_in_bits = 8*tag_type->abi_align;
+
+    ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+            ZigLLVMTypeToScope(union_type->llvm_di_type), "tag",
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            tag_debug_size_in_bits,
+            tag_debug_align_in_bits,
+            tag_offset_in_bits,
+            0, get_llvm_di_type(g, tag_type));
+
+    ZigLLVMDIType *di_root_members[2];
+    di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
+    di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type;
+
+    uint64_t debug_size_in_bits = union_type->size_in_bits;
+    uint64_t debug_align_in_bits = 8*union_type->abi_align;
+    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+            ZigLLVMFileToScope(import->data.structure.root_struct->di_file),
+            buf_ptr(&union_type->name),
+            import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1),
+            debug_size_in_bits,
+            debug_align_in_bits,
+            0, nullptr, di_root_members, 2, 0, nullptr, "");
+
+    ZigLLVMReplaceTemporary(g->dbuilder, union_type->llvm_di_type, replacement_di_type);
+    union_type->llvm_di_type = replacement_di_type;
+}
+
+static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
+    ZigType *elem_type = type->data.pointer.child_type;
+
+    if (type->data.pointer.is_const || type->data.pointer.is_volatile ||
+        type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle ||
+        type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero)
+    {
+        ZigType *peer_type = get_pointer_to_type_extra(g, elem_type, false, false,
+                PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false);
+        type->llvm_type = get_llvm_type(g, peer_type);
+        type->llvm_di_type = get_llvm_di_type(g, peer_type);
+        return;
+    }
+
+    if (type->data.pointer.host_int_bytes == 0) {
+        type->llvm_type = LLVMPointerType(get_llvm_type(g, elem_type), 0);
+        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
+        uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type);
+        type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, elem_type),
+                debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));
+    } else {
+        ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
+        LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);
+        type->llvm_type = LLVMPointerType(host_int_llvm_type, 0);
+        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, host_int_llvm_type);
+        uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, host_int_llvm_type);
+        type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, get_llvm_di_type(g, host_int_type),
+                debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));
+    }
+}
+
+static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) {
+    unsigned dwarf_tag;
+    if (type->data.integral.is_signed) {
+        if (type->size_in_bits == 8) {
+            dwarf_tag = ZigLLVMEncoding_DW_ATE_signed_char();
+        } else {
+            dwarf_tag = ZigLLVMEncoding_DW_ATE_signed();
+        }
+    } else {
+        if (type->size_in_bits == 8) {
+            dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned_char();
+        } else {
+            dwarf_tag = ZigLLVMEncoding_DW_ATE_unsigned();
+        }
+    }
+
+    type->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&type->name), type->size_in_bits, dwarf_tag);
+    type->llvm_type = LLVMIntType(type->size_in_bits);
+}
+
+static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) {
+    LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool);
+    ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool);
+
+    ZigType *child_type = type->data.maybe.child_type;
+    if (!type_has_bits(child_type)) {
+        type->llvm_type = bool_llvm_type;
+        type->llvm_di_type = bool_llvm_di_type;
+        return;
+    }
+
+    LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
+    ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
+
+    if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) {
+        type->llvm_type = child_llvm_type;
+        type->llvm_di_type = child_llvm_di_type;
+        return;
+    }
+
+    LLVMTypeRef elem_types[] = {
+        get_llvm_type(g, child_type),
+        LLVMInt1Type(),
+    };
+    type->llvm_type = LLVMStructType(elem_types, 2, false);
+
+    ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
+    ZigLLVMDIFile *di_file = nullptr;
+    unsigned line = 0;
+    type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+        ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name),
+        compile_unit_scope, di_file, line);
+
+    uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type);
+    uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type);
+    uint64_t val_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 0);
+
+    uint64_t maybe_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, bool_llvm_type);
+    uint64_t maybe_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, bool_llvm_type);
+    uint64_t maybe_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, 1);
+
+    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
+    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
+
+    ZigLLVMDIType *di_element_types[] = {
+        ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                "val", di_file, line,
+                val_debug_size_in_bits,
+                val_debug_align_in_bits,
+                val_offset_in_bits,
+                0, child_llvm_di_type),
+        ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                "maybe", di_file, line,
+                maybe_debug_size_in_bits,
+                maybe_debug_align_in_bits,
+                maybe_offset_in_bits,
+                0, bool_llvm_di_type),
+    };
+    ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+            compile_unit_scope,
+            buf_ptr(&type->name),
+            di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
+            nullptr, di_element_types, 2, 0, nullptr, "");
+
+    ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
+    type->llvm_di_type = replacement_di_type;
+}
+
+static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
+    ZigType *payload_type = type->data.error_union.payload_type;
+    ZigType *err_set_type = type->data.error_union.err_set_type;
+
+    if (!type_has_bits(payload_type)) {
+        assert(type_has_bits(err_set_type));
+        type->llvm_type = get_llvm_type(g, err_set_type);
+        type->llvm_di_type = get_llvm_di_type(g, err_set_type);
+    } else if (!type_has_bits(err_set_type)) {
+        type->llvm_type = get_llvm_type(g, payload_type);
+        type->llvm_di_type = get_llvm_di_type(g, payload_type);
+    } else {
+        LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
+        LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
+        LLVMTypeRef elem_types[2];
+        elem_types[err_union_err_index] = err_set_llvm_type;
+        elem_types[err_union_payload_index] = payload_llvm_type;
+        type->llvm_type = LLVMStructType(elem_types, 2, false);
+
+        ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
+        ZigLLVMDIFile *di_file = nullptr;
+        unsigned line = 0;
+        type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+            ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name),
+            compile_unit_scope, di_file, line);
+
+        uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_llvm_type);
+        uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_llvm_type);
+        uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type, err_union_err_index);
+
+        uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_llvm_type);
+        uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_llvm_type);
+        uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, type->llvm_type,
+                err_union_payload_index);
+
+        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
+
+        ZigLLVMDIType *di_element_types[] = {
+            ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                    "tag", di_file, line,
+                    tag_debug_size_in_bits,
+                    tag_debug_align_in_bits,
+                    tag_offset_in_bits,
+                    0, get_llvm_di_type(g, err_set_type)),
+            ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
+                    "value", di_file, line,
+                    value_debug_size_in_bits,
+                    value_debug_align_in_bits,
+                    value_offset_in_bits,
+                    0, get_llvm_di_type(g, payload_type)),
+        };
+
+        ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+                compile_unit_scope,
+                buf_ptr(&type->name),
+                di_file, line,
+                debug_size_in_bits,
+                debug_align_in_bits,
+                0,
+                nullptr, di_element_types, 2, 0, nullptr, "");
+
+        ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
+        type->llvm_di_type = replacement_di_type;
+    }
+}
+
+static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
+    ZigType *elem_type = type->data.array.child_type;
+
+    // TODO https://github.com/ziglang/zig/issues/1424
+    type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)type->data.array.len);
+
+    uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
+    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
+
+    type->llvm_di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits,
+            debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
+}
+
+static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
+    FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
+    bool first_arg_return = want_first_arg_sret(g, fn_type_id);
+    bool is_async = fn_type_id->cc == CallingConventionAsync;
+    bool is_c_abi = fn_type_id->cc == CallingConventionC;
+    bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
+    // +1 for maybe making the first argument the return value
+    // +1 for maybe first argument the error return trace
+    // +2 for maybe arguments async allocator and error code pointer
+    ZigList<LLVMTypeRef> gen_param_types = {};
+    // +1 because 0 is the return type and
+    // +1 for maybe making first arg ret val and
+    // +1 for maybe first argument the error return trace
+    // +2 for maybe arguments async allocator and error code pointer
+    ZigList<ZigLLVMDIType *> param_di_types = {};
+    param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
+    ZigType *gen_return_type;
+    if (is_async) {
+        gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
+    } else if (!type_has_bits(fn_type_id->return_type)) {
+        gen_return_type = g->builtin_types.entry_void;
+    } else if (first_arg_return) {
+        ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
+        gen_param_types.append(get_llvm_type(g, gen_type));
+        param_di_types.append(get_llvm_di_type(g, gen_type));
+        gen_return_type = g->builtin_types.entry_void;
+    } else {
+        gen_return_type = fn_type_id->return_type;
+    }
+    fn_type->data.fn.gen_return_type = gen_return_type;
+
+    if (prefix_arg_error_return_trace) {
+        ZigType *gen_type = get_ptr_to_stack_trace_type(g);
+        gen_param_types.append(get_llvm_type(g, gen_type));
+        param_di_types.append(get_llvm_di_type(g, gen_type));
+    }
+    if (is_async) {
+        {
+            // async allocator param
+            ZigType *gen_type = fn_type_id->async_allocator_type;
+            gen_param_types.append(get_llvm_type(g, gen_type));
+            param_di_types.append(get_llvm_di_type(g, gen_type));
+        }
+
+        {
+            // error code pointer
+            ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
+            gen_param_types.append(get_llvm_type(g, gen_type));
+            param_di_types.append(get_llvm_di_type(g, gen_type));
+        }
+    }
+
+    fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
+    for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
+        FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
+        ZigType *type_entry = src_param_info->type;
+        FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
+
+        gen_param_info->src_index = i;
+        gen_param_info->gen_index = SIZE_MAX;
+
+        if (!type_has_bits(type_entry))
+            continue;
+
+        ZigType *gen_type;
+        if (handle_is_ptr(type_entry)) {
+            gen_type = get_pointer_to_type(g, type_entry, true);
+            gen_param_info->is_byval = true;
+        } else {
+            gen_type = type_entry;
+        }
+        gen_param_info->gen_index = gen_param_types.length;
+        gen_param_info->type = gen_type;
+        gen_param_types.append(get_llvm_type(g, gen_type));
+
+        param_di_types.append(get_llvm_di_type(g, gen_type));
+    }
+
+    if (is_c_abi) {
+        FnWalk fn_walk = {};
+        fn_walk.id = FnWalkIdTypes;
+        fn_walk.data.types.param_di_types = &param_di_types;
+        fn_walk.data.types.gen_param_types = &gen_param_types;
+        walk_function_params(g, fn_type, &fn_walk);
+    }
+
+    fn_type->data.fn.gen_param_count = gen_param_types.length;
+
+    for (size_t i = 0; i < gen_param_types.length; i += 1) {
+        assert(gen_param_types.items[i] != nullptr);
+    }
+    fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
+            gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
+    fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
+    fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
+    fn_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type,
+            LLVMStoreSizeOfType(g->target_data_ref, fn_type->llvm_type),
+            LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
+}
+
+static void resolve_llvm_types_anyerror(CodeGen *g) {
+    ZigType *entry = g->builtin_types.entry_global_error_set;
+    entry->llvm_type = get_llvm_type(g, g->err_tag_type);
+    ZigList<ZigLLVMDIEnumerator *> err_enumerators;
+    // reserve index 0 to indicate no error
+    err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0));
+    for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
+        ErrorTableEntry *error_entry = g->errors_by_index.at(i);
+        err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&error_entry->name), i));
+    }
+
+    // create debug type for error sets
+    uint64_t tag_debug_size_in_bits = g->err_tag_type->size_in_bits;
+    uint64_t tag_debug_align_in_bits = 8*g->err_tag_type->abi_align;
+    ZigLLVMDIFile *err_set_di_file = nullptr;
+    entry->llvm_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+            ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&entry->name),
+            err_set_di_file, 0,
+            tag_debug_size_in_bits,
+            tag_debug_align_in_bits,
+            err_enumerators.items, err_enumerators.length,
+            get_llvm_di_type(g, g->err_tag_type), "");
+}
+
+static void resolve_llvm_types(CodeGen *g, ZigType *type) {
+    assert(type_is_resolved(type, ResolveStatusSizeKnown));
+    assert(type_has_bits(type));
+    switch (type->id) {
+        case ZigTypeIdInvalid:
+        case ZigTypeIdFloat:
+        case ZigTypeIdOpaque:
+        case ZigTypeIdMetaType:
+        case ZigTypeIdVoid:
+        case ZigTypeIdBool:
+        case ZigTypeIdUnreachable:
+        case ZigTypeIdComptimeFloat:
+        case ZigTypeIdComptimeInt:
+        case ZigTypeIdEnumLiteral:
+        case ZigTypeIdUndefined:
+        case ZigTypeIdNull:
+        case ZigTypeIdBoundFn:
+        case ZigTypeIdArgTuple:
+            zig_unreachable();
+        case ZigTypeIdStruct:
+            if (type->data.structure.is_slice)
+                return resolve_llvm_types_slice(g, type);
+            else
+                return resolve_llvm_types_struct(g, type);
+        case ZigTypeIdEnum:
+            return resolve_llvm_types_enum(g, type);
+        case ZigTypeIdUnion:
+            return resolve_llvm_types_union(g, type);
+        case ZigTypeIdPointer:
+            return resolve_llvm_types_pointer(g, type);
+        case ZigTypeIdPromise: {
+            ZigType *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
+            type->llvm_type = get_llvm_type(g, u8_ptr_type);
+            type->llvm_di_type = get_llvm_di_type(g, u8_ptr_type);
+            return;
+        }
+        case ZigTypeIdInt:
+            return resolve_llvm_types_integer(g, type);
+        case ZigTypeIdOptional:
+            return resolve_llvm_types_optional(g, type);
+        case ZigTypeIdErrorUnion:
+            return resolve_llvm_types_error_union(g, type);
+        case ZigTypeIdArray:
+            return resolve_llvm_types_array(g, type);
+        case ZigTypeIdFn:
+            return resolve_llvm_types_fn(g, type);
+        case ZigTypeIdErrorSet: {
+            if (g->builtin_types.entry_global_error_set->llvm_type == nullptr) {
+                resolve_llvm_types_anyerror(g);
+            }
+            type->llvm_type = g->builtin_types.entry_global_error_set->llvm_type;
+            type->llvm_di_type = g->builtin_types.entry_global_error_set->llvm_di_type;
+            return;
+        }
+        case ZigTypeIdVector: {
+            type->llvm_type = LLVMVectorType(get_llvm_type(g, type->data.vector.elem_type), type->data.vector.len);
+            type->llvm_di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, type->size_in_bits,
+                    type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);
+            return;
+        }
+    }
+    zig_unreachable();
+}
+
+LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {
+    if (type->llvm_type != nullptr)
+        return type->llvm_type;
+    resolve_llvm_types(g, type);
+    assert(type->llvm_type != nullptr);
+    assert(type->llvm_di_type != nullptr);
+    assert(type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
+    assert(type->abi_align == LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
+    return type->llvm_type;
+}
+
+ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type) {
+    if (type->llvm_di_type != nullptr)
+        return type->llvm_di_type;
+    resolve_llvm_types(g, type);
+    assert(type->llvm_type != nullptr);
+    assert(type->llvm_di_type != nullptr);
+    assert(type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
+    assert(type->abi_align == LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
+    return type->llvm_di_type;
+}
src/analyze.hpp
@@ -244,4 +244,6 @@ Buf *type_bare_name(ZigType *t);
 Buf *type_h_name(ZigType *t);
 Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose);
 
+LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type);
+ZigLLVMDIType *get_llvm_di_type(CodeGen *g, ZigType *type);
 #endif
src/codegen.cpp
@@ -668,7 +668,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
             if (scope->parent) {
                 ScopeDecls *decls_scope = (ScopeDecls *)scope;
                 assert(decls_scope->container_type);
-                scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
+                scope->di_scope = ZigLLVMTypeToScope(get_llvm_di_type(g, decls_scope->container_type));
             } else {
                 scope->di_scope = ZigLLVMFileToScope(import->data.structure.root_struct->di_file);
             }
@@ -711,8 +711,8 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type
     const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name;
 
     LLVMTypeRef param_types[] = {
-        operand_type->type_ref,
-        operand_type->type_ref,
+        get_llvm_type(g, operand_type),
+        get_llvm_type(g, operand_type),
     };
 
     if (operand_type->id == ZigTypeIdVector) {
@@ -720,7 +720,7 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type
                 operand_type->data.vector.len, int_type->data.integral.bit_count);
 
         LLVMTypeRef return_elem_types[] = {
-            operand_type->type_ref,
+            get_llvm_type(g, operand_type),
             LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len),
         };
         LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
@@ -732,7 +732,7 @@ static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type
         sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count);
 
         LLVMTypeRef return_elem_types[] = {
-            operand_type->type_ref,
+            get_llvm_type(g, operand_type),
             LLVMInt1Type(),
         };
         LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
@@ -800,7 +800,8 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn
 
     char fn_name[64];
     sprintf(fn_name, "llvm.%s.f%" ZIG_PRI_usize "", name, type_entry->data.floating.bit_count);
-    LLVMTypeRef fn_type = LLVMFunctionType(type_entry->type_ref, &type_entry->type_ref, 1, false);
+    LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry);
+    LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, &float_type_ref, 1, false);
     LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);
     assert(LLVMGetIntrinsicID(fn_val));
 
@@ -958,7 +959,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
     ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
             PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
     ZigType *str_type = get_slice_type(g, u8_ptr_type);
-    return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
+    return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));
 }
 
 static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
@@ -967,7 +968,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace
     LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
     if (stack_trace_arg == nullptr) {
         ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
-        stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
+        stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
     }
     LLVMValueRef args[] = {
         msg_arg,
@@ -1081,7 +1082,7 @@ static LLVMValueRef get_coro_size_fn_val(CodeGen *g) {
     if (g->coro_size_fn_val)
         return g->coro_size_fn_val;
 
-    LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->type_ref, nullptr, 0, false);
+    LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->llvm_type, nullptr, 0, false);
     Buf *name = buf_sprintf("llvm.coro.size.i%d", g->pointer_size_bytes * 8);
     g->coro_size_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
     assert(LLVMGetIntrinsicID(g->coro_size_fn_val));
@@ -1206,8 +1207,8 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
 
     ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
 
-    LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref,
-            &g->builtin_types.entry_i32->type_ref, 1, false);
+    LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type),
+            &g->builtin_types.entry_i32->llvm_type, 1, false);
     g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type);
     assert(LLVMGetIntrinsicID(g->return_address_fn_val));
 
@@ -1219,8 +1220,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
         return g->add_error_return_trace_addr_fn_val;
 
     LLVMTypeRef arg_types[] = {
-        get_ptr_to_stack_trace_type(g)->type_ref,
-        g->builtin_types.entry_usize->type_ref,
+        get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
+        g->builtin_types.entry_usize->llvm_type,
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
 
@@ -1245,7 +1246,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
     LLVMPositionBuilderAtEnd(g->builder, entry_block);
     ZigLLVMClearCurrentDebugLocation(g->builder);
 
-    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
+    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
 
     // stack_trace.instruction_addresses[stack_trace.index & (stack_trace.instruction_addresses.len - 1)] = return_address;
 
@@ -1297,8 +1298,8 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
     assert(g->stack_trace_type != nullptr);
 
     LLVMTypeRef param_types[] = {
-        get_ptr_to_stack_trace_type(g)->type_ref,
-        get_ptr_to_stack_trace_type(g)->type_ref,
+        get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
+        get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
 
@@ -1350,8 +1351,8 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
     // }
     LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
 
-    LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index");
-    LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left");
+    LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
+    LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
 
     LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
     LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
@@ -1377,14 +1378,14 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
     LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
 
     LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
-    LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
+    LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
     LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
     LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
     LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
     LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
 
     LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
-    LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
+    LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
     LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
     LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
     LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
@@ -1430,7 +1431,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
 
     LLVMTypeRef arg_types[] = {
         // error return trace pointer
-        get_ptr_to_stack_trace_type(g)->type_ref,
+        get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
 
@@ -1461,8 +1462,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
 
     LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
 
-    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
-    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_i32));
     LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
     LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
 
@@ -1508,8 +1509,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
 
     ZigType *usize = g->builtin_types.entry_usize;
     LLVMValueRef full_buf_ptr_indices[] = {
-        LLVMConstNull(usize->type_ref),
-        LLVMConstNull(usize->type_ref),
+        LLVMConstNull(usize->llvm_type),
+        LLVMConstNull(usize->llvm_type),
     };
     LLVMValueRef full_buf_ptr = LLVMConstInBoundsGEP(global_array, full_buf_ptr_indices, 2);
 
@@ -1519,9 +1520,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
     ZigType *str_type = get_slice_type(g, u8_ptr_type);
     LLVMValueRef global_slice_fields[] = {
         full_buf_ptr,
-        LLVMConstNull(usize->type_ref),
+        LLVMConstNull(usize->llvm_type),
     };
-    LLVMValueRef slice_init_value = LLVMConstNamedStruct(str_type->type_ref, global_slice_fields, 2);
+    LLVMValueRef slice_init_value = LLVMConstNamedStruct(get_llvm_type(g, str_type), global_slice_fields, 2);
     LLVMValueRef global_slice = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
     LLVMSetInitializer(global_slice, slice_init_value);
     LLVMSetLinkage(global_slice, LLVMInternalLinkage);
@@ -1530,15 +1531,15 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
     LLVMSetAlignment(global_slice, get_abi_alignment(g, str_type));
 
     LLVMValueRef offset_ptr_indices[] = {
-        LLVMConstNull(usize->type_ref),
-        LLVMConstInt(usize->type_ref, unwrap_err_msg_text_len, false),
+        LLVMConstNull(usize->llvm_type),
+        LLVMConstInt(usize->llvm_type, unwrap_err_msg_text_len, false),
     };
     LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
 
     Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
     LLVMTypeRef arg_types[] = {
-        g->ptr_to_stack_trace_type->type_ref,
-        g->err_tag_type->type_ref,
+        get_llvm_type(g, g->ptr_to_stack_trace_type),
+        get_llvm_type(g, g->err_tag_type),
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
     LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
@@ -1565,7 +1566,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
     LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
 
     LLVMValueRef err_table_indices[] = {
-        LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+        LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
         err_val,
     };
     LLVMValueRef err_name_val = LLVMBuildInBoundsGEP(g->builder, g->err_name_table, err_table_indices, 2, "");
@@ -1623,7 +1624,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
     LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
     if (err_ret_trace_val == nullptr) {
         ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
-        err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
+        err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
     }
     LLVMValueRef args[] = {
         err_ret_trace_val,
@@ -1669,7 +1670,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
 }
 
 static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) {
-    LLVMValueRef zero = LLVMConstNull(int_type->type_ref);
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type));
     LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, "");
     LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
     LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
@@ -1704,7 +1705,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
         !wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
         want_runtime_safety)
     {
-        LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
+        LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, actual_type));
         LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
 
         LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk");
@@ -1721,19 +1722,19 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
         return expr_val;
     } else if (actual_bits < wanted_bits) {
         if (actual_type->id == ZigTypeIdFloat) {
-            return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildFPExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
         } else if (actual_type->id == ZigTypeIdInt) {
             if (actual_type->data.integral.is_signed) {
-                return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
+                return LLVMBuildSExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             } else {
-                return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+                return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             }
         } else {
             zig_unreachable();
         }
     } else if (actual_bits > wanted_bits) {
         if (actual_type->id == ZigTypeIdFloat) {
-            return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildFPTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
         } else if (actual_type->id == ZigTypeIdInt) {
             if (wanted_bits == 0) {
                 if (!want_runtime_safety)
@@ -1741,15 +1742,15 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
 
                 return gen_assert_zero(g, expr_val, actual_type);
             }
-            LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
+            LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             if (!want_runtime_safety) {
                 return trunc_val;
             }
             LLVMValueRef orig_val;
             if (wanted_type->data.integral.is_signed) {
-                orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");
+                orig_val = LLVMBuildSExt(g->builder, trunc_val, get_llvm_type(g, actual_type), "");
             } else {
-                orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
+                orig_val = LLVMBuildZExt(g->builder, trunc_val, get_llvm_type(g, actual_type), "");
             }
             LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, "");
             LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
@@ -1793,7 +1794,7 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul
         LLVMValueRef extended1 = buildExtFn(g->builder, val1, one_more_bit_int_vector, "");
         LLVMValueRef extended2 = buildExtFn(g->builder, val2, one_more_bit_int_vector, "");
         LLVMValueRef extended_result = wrap_op[op](g->builder, extended1, extended2, "");
-        result = LLVMBuildTrunc(g->builder, extended_result, operand_type->type_ref, "");
+        result = LLVMBuildTrunc(g->builder, extended_result, get_llvm_type(g, operand_type), "");
 
         LLVMValueRef re_extended_result = buildExtFn(g->builder, result, one_more_bit_int_vector, "");
         LLVMValueRef overflow_vector = LLVMBuildICmp(g->builder, LLVMIntNE, extended_result, re_extended_result, "");
@@ -1880,12 +1881,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
         LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
 
         ZigType *usize = g->builtin_types.entry_usize;
-        uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
+        uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, child_type));
         uint64_t align_bytes = get_ptr_align(g, ptr_type);
         assert(size_bytes > 0);
         assert(align_bytes > 0);
 
-        ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes, LLVMConstInt(usize->type_ref, size_bytes, false),
+        ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,
+                LLVMConstInt(usize->llvm_type, size_bytes, false),
                 ptr_type->data.pointer.is_volatile);
         return nullptr;
     }
@@ -1907,7 +1909,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
     uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - size_in_bits : bit_offset;
     LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
 
-    LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
+    LLVMValueRef mask_val = LLVMConstAllOnes(get_llvm_type(g, child_type));
     mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
     mask_val = LLVMConstShl(mask_val, shift_amt_val);
     mask_val = LLVMConstNot(mask_val);
@@ -1942,9 +1944,10 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
         if (handle_is_ptr(instruction->value.type)) {
             render_const_val_global(g, &instruction->value, "");
             ZigType *ptr_type = get_pointer_to_type(g, instruction->value.type, true);
-            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_global, ptr_type->type_ref, "");
+            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_global, get_llvm_type(g, ptr_type), "");
         } else if (instruction->value.type->id == ZigTypeIdPointer) {
-            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_value, instruction->value.type->type_ref, "");
+            instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_value,
+                    get_llvm_type(g, instruction->value.type), "");
         } else {
             instruction->llvm_value = instruction->value.global_refs->llvm_value;
         }
@@ -1979,7 +1982,7 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
 }
 
 static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
-    LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
+    LLVMValueRef result = LLVMBuildAlloca(g->builder, get_llvm_type(g, type_entry), name);
     LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment);
     return result;
 }
@@ -2062,8 +2065,8 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                 fn_walk->data.call.gen_param_values->append(val);
                 break;
             case FnWalkIdTypes:
-                fn_walk->data.types.gen_param_types->append(ty->type_ref);
-                fn_walk->data.types.param_di_types->append(ty->di_type);
+                fn_walk->data.types.gen_param_types->append(get_llvm_type(g, ty));
+                fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, ty));
                 break;
             case FnWalkIdVars: {
                 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
@@ -2099,8 +2102,8 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                 break;
             case FnWalkIdTypes: {
                 ZigType *gen_type = get_pointer_to_type(g, ty, true);
-                fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
-                fn_walk->data.types.param_di_types->append(gen_type->di_type);
+                fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type));
+                fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type));
                 break;
             }
             case FnWalkIdVars: {
@@ -2138,8 +2141,8 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                     break;
                 case FnWalkIdTypes: {
                     ZigType *gen_type = get_pointer_to_type(g, ty, true);
-                    fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
-                    fn_walk->data.types.param_di_types->append(gen_type->di_type);
+                    fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type));
+                    fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type));
                     break;
                 }
                 case FnWalkIdVars: {
@@ -2171,8 +2174,8 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                 }
                 case FnWalkIdTypes: {
                     ZigType *gen_type = get_int_type(g, false, ty_size * 8);
-                    fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
-                    fn_walk->data.types.param_di_types->append(gen_type->di_type);
+                    fn_walk->data.types.gen_param_types->append(get_llvm_type(g, gen_type));
+                    fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, gen_type));
                     break;
                 }
                 case FnWalkIdVars: {
@@ -2210,7 +2213,7 @@ var_ok:
         var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
                 buf_ptr(&var->name), fn_walk->data.vars.import->data.structure.root_struct->di_file,
                 (unsigned)(var->decl_node->line + 1),
-                dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
+                get_llvm_di_type(g, dest_ty), !g->strip_debug_symbols, 0, di_arg_index + 1);
     }
     return true;
 }
@@ -2436,7 +2439,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
 {
     ZigLLVMSetFastMath(g->builder, want_fast_math);
 
-    LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, type_entry));
     if (want_runtime_safety && (want_fast_math || type_entry->id != ZigTypeIdFloat)) {
         LLVMValueRef is_zero_bit;
         if (type_entry->id == ZigTypeIdInt) {
@@ -2456,10 +2459,10 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
         LLVMPositionBuilderAtEnd(g->builder, div_zero_ok_block);
 
         if (type_entry->id == ZigTypeIdInt && type_entry->data.integral.is_signed) {
-            LLVMValueRef neg_1_value = LLVMConstInt(type_entry->type_ref, -1, true);
+            LLVMValueRef neg_1_value = LLVMConstInt(get_llvm_type(g, type_entry), -1, true);
             BigInt int_min_bi = {0};
             eval_min_max_value_int(g, type_entry, &int_min_bi, false);
-            LLVMValueRef int_min_value = bigint_to_llvm_const(type_entry->type_ref, &int_min_bi);
+            LLVMValueRef int_min_value = bigint_to_llvm_const(get_llvm_type(g, type_entry), &int_min_bi);
             LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk");
             LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail");
             LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, "");
@@ -2513,7 +2516,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
                     LLVMBuildBr(g->builder, end_block);
 
                     LLVMPositionBuilderAtEnd(g->builder, end_block);
-                    LLVMValueRef phi = LLVMBuildPhi(g->builder, type_entry->type_ref, "");
+                    LLVMValueRef phi = LLVMBuildPhi(g->builder, get_llvm_type(g, type_entry), "");
                     LLVMValueRef incoming_values[] = { ceiled, floored };
                     LLVMBasicBlockRef incoming_blocks[] = { ceiled_end_block, floored_end_block };
                     LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
@@ -2576,7 +2579,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
                 LLVMValueRef orig_num = LLVMBuildNSWMul(g->builder, result, val2, "");
                 LLVMValueRef orig_ok = LLVMBuildICmp(g->builder, LLVMIntEQ, orig_num, val1, "");
                 LLVMValueRef ok_bit = LLVMBuildOr(g->builder, orig_ok, is_pos, "");
-                LLVMValueRef one = LLVMConstInt(type_entry->type_ref, 1, true);
+                LLVMValueRef one = LLVMConstInt(get_llvm_type(g, type_entry), 1, true);
                 LLVMValueRef result_minus_1 = LLVMBuildNSWSub(g->builder, result, one, "");
                 return LLVMBuildSelect(g->builder, ok_bit, result, result_minus_1, "");
             }
@@ -2595,7 +2598,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
 {
     ZigLLVMSetFastMath(g->builder, want_fast_math);
 
-    LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, type_entry));
     if (want_runtime_safety) {
         LLVMValueRef is_zero_bit;
         if (type_entry->id == ZigTypeIdInt) {
@@ -2820,7 +2823,7 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in
     assert(err_set_type->id == ZigTypeIdErrorSet);
 
     if (type_is_global_error_set(err_set_type)) {
-        LLVMValueRef zero = LLVMConstNull(int_type->type_ref);
+        LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type));
         LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
         LLVMValueRef ok_bit;
 
@@ -2832,7 +2835,7 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in
         {
             ok_bit = neq_zero_bit;
         } else {
-            LLVMValueRef error_value_count = LLVMConstInt(int_type->type_ref, g->errors_by_index.length, false);
+            LLVMValueRef error_value_count = LLVMConstInt(get_llvm_type(g, int_type), g->errors_by_index.length, false);
             LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
             ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
         }
@@ -2853,7 +2856,8 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in
         uint32_t err_count = err_set_type->data.error_set.err_count;
         LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_val, fail_block, err_count);
         for (uint32_t i = 0; i < err_count; i += 1) {
-            LLVMValueRef case_value = LLVMConstInt(g->err_tag_type->type_ref, err_set_type->data.error_set.errors[i]->value, false);
+            LLVMValueRef case_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type),
+                    err_set_type->data.error_set.errors[i]->value, false);
             LLVMAddCase(switch_instr, case_value, ok_block);
         }
 
@@ -2892,7 +2896,7 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable,
     LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_ptr_index, "");
     LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
     LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
-            wanted_type->data.structure.fields[0].type_entry->type_ref, "");
+            get_llvm_type(g, wanted_type->data.structure.fields[0].type_entry), "");
     LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
             (unsigned)wanted_ptr_index, "");
     gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
@@ -2904,13 +2908,13 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable,
 
     LLVMValueRef new_len;
     if (dest_size == 1) {
-        LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
+        LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, src_size, false);
         new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
     } else if (src_size == 1) {
-        LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
+        LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, dest_size, false);
         if (ir_want_runtime_safety(g, &instruction->base)) {
             LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
-            LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
+            LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
             LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
             LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
             LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
@@ -2951,9 +2955,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
         case CastOpIntToFloat:
             assert(actual_type->id == ZigTypeIdInt);
             if (actual_type->data.integral.is_signed) {
-                return LLVMBuildSIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+                return LLVMBuildSIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             } else {
-                return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+                return LLVMBuildUIToFP(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             }
         case CastOpFloatToInt: {
             assert(wanted_type->id == ZigTypeIdInt);
@@ -2963,9 +2967,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
 
             LLVMValueRef result;
             if (wanted_type->data.integral.is_signed) {
-                result = LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
+                result = LLVMBuildFPToSI(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             } else {
-                result = LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
+                result = LLVMBuildFPToUI(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
             }
 
             if (want_safety) {
@@ -2993,14 +2997,14 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
         case CastOpBoolToInt:
             assert(wanted_type->id == ZigTypeIdInt);
             assert(actual_type->id == ZigTypeIdBool);
-            return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildZExt(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
         case CastOpErrSet:
             if (ir_want_runtime_safety(g, &cast_instruction->base)) {
                 add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
             }
             return expr_val;
         case CastOpBitCast:
-            return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), "");
         case CastOpPtrOfArrayToSlice: {
             assert(cast_instruction->tmp_ptr);
             assert(actual_type->id == ZigTypeIdPointer);
@@ -3010,15 +3014,15 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
             LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
                     slice_ptr_index, "");
             LLVMValueRef indices[] = {
-                LLVMConstNull(g->builtin_types.entry_usize->type_ref),
-                LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
+                LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
+                LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false),
             };
             LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
             gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
 
             LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
                     slice_len_index, "");
-            LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+            LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
                     array_type->data.array.len, false);
             gen_store_untyped(g, len_value, len_field_ptr, 0, false);
 
@@ -3036,7 +3040,7 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
         return nullptr;
     }
     LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
-    LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
+    LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, get_llvm_type(g, wanted_type), "");
     bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
     if (!want_safety_check || ptr_allows_addr_zero(wanted_type))
         return result_ptr;
@@ -3066,16 +3070,16 @@ static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
     if (wanted_is_ptr == actual_is_ptr) {
         // We either bitcast the value directly or bitcast the pointer which does a pointer cast
         LLVMTypeRef wanted_type_ref = wanted_is_ptr ?
-            LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref;
+            LLVMPointerType(get_llvm_type(g, wanted_type), 0) : get_llvm_type(g, wanted_type);
         return LLVMBuildBitCast(g->builder, value, wanted_type_ref, "");
     } else if (actual_is_ptr) {
-        LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(wanted_type->type_ref, 0);
+        LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, wanted_type), 0);
         LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, "");
         uint32_t alignment = get_abi_alignment(g, actual_type);
         return gen_load_untyped(g, bitcasted_ptr, alignment, false, "");
     } else {
         assert(instruction->tmp_ptr != nullptr);
-        LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(actual_type->type_ref, 0);
+        LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, actual_type), 0);
         LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, "");
         uint32_t alignment = get_abi_alignment(g, wanted_type);
         gen_store_untyped(g, value, bitcasted_ptr, alignment, false);
@@ -3115,13 +3119,13 @@ static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, IrExecutable *executable, I
 
         LLVMPositionBuilderAtEnd(g->builder, ok_block);
     }
-    return LLVMBuildIntToPtr(g->builder, target_val, wanted_type->type_ref, "");
+    return LLVMBuildIntToPtr(g->builder, target_val, get_llvm_type(g, wanted_type), "");
 }
 
 static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, IrInstructionPtrToInt *instruction) {
     ZigType *wanted_type = instruction->base.value.type;
     LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
-    return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, "");
+    return LLVMBuildPtrToInt(g->builder, target_val, get_llvm_type(g, wanted_type), "");
 }
 
 static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) {
@@ -3139,7 +3143,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
         size_t field_count = wanted_type->data.enumeration.src_field_count;
         LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
         for (size_t field_i = 0; field_i < field_count; field_i += 1) {
-            LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
+            LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
                     &wanted_type->data.enumeration.fields[field_i].value);
             LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
         }
@@ -3321,7 +3325,7 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
     LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
 
     if (!handle_is_ptr(child_type))
-        return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
+        return LLVMBuildTrunc(g->builder, shifted_value, get_llvm_type(g, child_type), "");
 
     assert(instruction->tmp_ptr != nullptr);
     LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
@@ -3378,7 +3382,7 @@ static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default
     if (!target_has_valgrind_support(g->zig_target)) {
         return default_value;
     }
-    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
+    LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
     bool asm_has_side_effects = true;
     bool asm_is_alignstack = false;
     if (g->zig_target->arch == ZigLLVM_x86_64) {
@@ -3445,7 +3449,7 @@ static bool want_valgrind_support(CodeGen *g) {
 
 static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
     assert(type_has_bits(value_type));
-    uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
+    uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, value_type));
     assert(size_bytes > 0);
     assert(ptr_align_bytes > 0);
     // memset uninitialized memory to 0xaa
@@ -3453,14 +3457,14 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_
     LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
     LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
     ZigType *usize = g->builtin_types.entry_usize;
-    LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+    LLVMValueRef byte_count = LLVMConstInt(usize->llvm_type, size_bytes, false);
     ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
     // then tell valgrind that the memory is undefined even though we just memset it
     if (want_valgrind_support(g)) {
         static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
-        LLVMValueRef zero = LLVMConstInt(usize->type_ref, 0, false);
-        LLVMValueRef req = LLVMConstInt(usize->type_ref, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
-        LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->type_ref, "");
+        LLVMValueRef zero = LLVMConstInt(usize->llvm_type, 0, false);
+        LLVMValueRef req = LLVMConstInt(usize->llvm_type, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
+        LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->llvm_type, "");
         gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero);
     }
 }
@@ -3515,7 +3519,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
             array_type = array_type->data.pointer.child_type;
         }
         if (safety_check_on) {
-            LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+            LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
                     array_type->data.array.len, false);
             add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
         }
@@ -3533,18 +3537,18 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
                 LLVMTypeRef ptr_u8_type_ref = LLVMPointerType(LLVMInt8Type(), 0);
                 LLVMValueRef u8_array_ptr = LLVMBuildBitCast(g->builder, array_ptr, ptr_u8_type_ref, "");
                 assert(size_in_bits % 8 == 0);
-                LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+                LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
                         size_in_bits / 8, false);
                 LLVMValueRef byte_offset = LLVMBuildNUWMul(g->builder, subscript_value, elem_size_bytes, "");
                 LLVMValueRef indices[] = {
                     byte_offset
                 };
                 LLVMValueRef elem_byte_ptr = LLVMBuildInBoundsGEP(g->builder, u8_array_ptr, indices, 1, "");
-                return LLVMBuildBitCast(g->builder, elem_byte_ptr, LLVMPointerType(child_type->type_ref, 0), "");
+                return LLVMBuildBitCast(g->builder, elem_byte_ptr, LLVMPointerType(get_llvm_type(g, child_type), 0), "");
             }
         }
         LLVMValueRef indices[] = {
-            LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+            LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
             subscript_value
         };
         return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
@@ -3773,7 +3777,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
         return nullptr;
 
     LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);
-    LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
+    LLVMTypeRef field_type_ref = LLVMPointerType(get_llvm_type(g, field->type_entry), 0);
 
     if (union_type->data.unionation.gen_tag_index == SIZE_MAX) {
         LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, "");
@@ -3786,7 +3790,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
         LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
 
 
-        LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+        LLVMValueRef expected_tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type),
                 &field->enum_field->value);
         LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
         LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
@@ -3916,7 +3920,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
         }
 
         ZigType *const type = ir_input->value.type;
-        LLVMTypeRef type_ref = type->type_ref;
+        LLVMTypeRef type_ref = get_llvm_type(g, type);
         LLVMValueRef value_ref = ir_llvm_value(g, ir_input);
         // Handle integers of non pot bitsize by widening them.
         if (type->id == ZigTypeIdInt) {
@@ -3925,7 +3929,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
                 const bool is_signed = type->data.integral.is_signed;
                 const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize);
                 ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize);
-                type_ref = wider_type->type_ref;
+                type_ref = get_llvm_type(g, wider_type);
                 value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref);
             }
         }
@@ -3945,7 +3949,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
     if (instruction->return_count == 0) {
         ret_type = LLVMVoidType();
     } else {
-        ret_type = instruction->base.value.type->type_ref;
+        ret_type = get_llvm_type(g, instruction->base.value.type);
     }
     LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false);
 
@@ -3964,7 +3968,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
     } else {
         bool is_scalar = !handle_is_ptr(maybe_type);
         if (is_scalar) {
-            return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
+            return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(get_llvm_type(g, maybe_type)), "");
         } else {
             LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
             return gen_load_untyped(g, maybe_field_ptr, 0, false, "");
@@ -3999,7 +4003,7 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec
 
         LLVMPositionBuilderAtEnd(g->builder, ok_block);
     }
-    if (child_type->zero_bits) {
+    if (!type_has_bits(child_type)) {
         return nullptr;
     } else {
         bool is_scalar = !handle_is_ptr(maybe_type);
@@ -4052,10 +4056,10 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
     char llvm_name[64];
     sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count);
     LLVMTypeRef param_types[] = {
-        int_type->type_ref,
+        get_llvm_type(g, int_type),
         LLVMInt1Type(),
     };
-    LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, n_args, false);
+    LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, int_type), param_types, n_args, false);
     LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type);
     assert(LLVMGetIntrinsicID(fn_val));
 
@@ -4114,9 +4118,9 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru
 
     LLVMTypeRef phi_type;
     if (handle_is_ptr(instruction->base.value.type)) {
-        phi_type = LLVMPointerType(instruction->base.value.type->type_ref, 0);
+        phi_type = LLVMPointerType(get_llvm_type(g,instruction->base.value.type), 0);
     } else {
-        phi_type = instruction->base.value.type->type_ref;
+        phi_type = get_llvm_type(g, instruction->base.value.type);
     }
 
     LLVMValueRef phi = LLVMBuildPhi(g->builder, phi_type, "");
@@ -4160,7 +4164,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
     }
 
     LLVMValueRef indices[] = {
-        LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+        LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
         err_val,
     };
     return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, "");
@@ -4176,8 +4180,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
     ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type);
     ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type;
 
-    LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0),
-            &tag_int_type->type_ref, 1, false);
+    LLVMTypeRef tag_int_llvm_type = get_llvm_type(g, tag_int_type);
+    LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0),
+            &tag_int_llvm_type, 1, false);
     
     Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
     LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
@@ -4209,8 +4214,8 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
 
     ZigType *usize = g->builtin_types.entry_usize;
     LLVMValueRef array_ptr_indices[] = {
-        LLVMConstNull(usize->type_ref),
-        LLVMConstNull(usize->type_ref),
+        LLVMConstNull(usize->llvm_type),
+        LLVMConstNull(usize->llvm_type),
     };
 
     for (size_t field_i = 0; field_i < field_count; field_i += 1) {
@@ -4225,9 +4230,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
 
         LLVMValueRef fields[] = {
             LLVMConstGEP(str_global, array_ptr_indices, 2),
-            LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
+            LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false),
         };
-        LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2);
+        LLVMValueRef slice_init_value = LLVMConstNamedStruct(get_llvm_type(g, u8_slice_type), fields, 2);
 
         LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), "");
         LLVMSetInitializer(slice_global, slice_init_value);
@@ -4237,7 +4242,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
         LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value)));
 
         LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name");
-        LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
+        LLVMValueRef this_tag_int_value = bigint_to_llvm_const(get_llvm_type(g, tag_int_type),
                 &enum_type->data.enumeration.fields[field_i].value);
         LLVMAddCase(switch_instr, this_tag_int_value, return_block);
 
@@ -4283,22 +4288,21 @@ static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executa
     ZigType *container_type = container_ptr_type->data.pointer.child_type;
 
     size_t byte_offset = LLVMOffsetOfElement(g->target_data_ref,
-            container_type->type_ref, instruction->field->gen_index);
+            get_llvm_type(g, container_type), instruction->field->gen_index);
 
     LLVMValueRef field_ptr_val = ir_llvm_value(g, instruction->field_ptr);
 
     if (byte_offset == 0) {
-        return LLVMBuildBitCast(g->builder, field_ptr_val, container_ptr_type->type_ref, "");
+        return LLVMBuildBitCast(g->builder, field_ptr_val, get_llvm_type(g, container_ptr_type), "");
     } else {
         ZigType *usize = g->builtin_types.entry_usize;
 
-        LLVMValueRef field_ptr_int = LLVMBuildPtrToInt(g->builder, field_ptr_val,
-                usize->type_ref, "");
+        LLVMValueRef field_ptr_int = LLVMBuildPtrToInt(g->builder, field_ptr_val, usize->llvm_type, "");
 
         LLVMValueRef base_ptr_int = LLVMBuildNUWSub(g->builder, field_ptr_int,
-                LLVMConstInt(usize->type_ref, byte_offset, false), "");
+                LLVMConstInt(usize->llvm_type, byte_offset, false), "");
 
-        return LLVMBuildIntToPtr(g->builder, base_ptr_int, container_ptr_type->type_ref, "");
+        return LLVMBuildIntToPtr(g->builder, base_ptr_int, get_llvm_type(g, container_ptr_type), "");
     }
 }
 
@@ -4349,10 +4353,10 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
     assert(align_bytes != 1);
 
     ZigType *usize = g->builtin_types.entry_usize;
-    LLVMValueRef ptr_as_int_val = LLVMBuildPtrToInt(g->builder, ptr_val, usize->type_ref, "");
-    LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->type_ref, align_bytes - 1, false);
+    LLVMValueRef ptr_as_int_val = LLVMBuildPtrToInt(g->builder, ptr_val, usize->llvm_type, "");
+    LLVMValueRef alignment_minus_1 = LLVMConstInt(usize->llvm_type, align_bytes - 1, false);
     LLVMValueRef anded_val = LLVMBuildAnd(g->builder, ptr_as_int_val, alignment_minus_1, "");
-    LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, LLVMConstNull(usize->type_ref), "");
+    LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, anded_val, LLVMConstNull(usize->llvm_type), "");
 
     LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastOk");
     LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "AlignCastFail");
@@ -4373,7 +4377,7 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
     LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
     if (cur_err_ret_trace_val == nullptr) {
         ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
-        return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
+        return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
     }
     return cur_err_ret_trace_val;
 }
@@ -4439,7 +4443,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
     if (!handle_is_ptr(maybe_type)) {
         LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
         LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
-        return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
+        return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
     }
 
     assert(instruction->tmp_ptr != nullptr);
@@ -4470,10 +4474,10 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI
         // no-op
         return target_val;
     } if (src_type->data.integral.bit_count == dest_type->data.integral.bit_count) {
-        return LLVMBuildBitCast(g->builder, target_val, dest_type->type_ref, "");
+        return LLVMBuildBitCast(g->builder, target_val, get_llvm_type(g, dest_type), "");
     } else {
         LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
-        return LLVMBuildTrunc(g->builder, target_val, dest_type->type_ref, "");
+        return LLVMBuildTrunc(g->builder, target_val, get_llvm_type(g, dest_type), "");
     }
 }
 
@@ -4539,12 +4543,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
         if (instruction->end) {
             end_val = ir_llvm_value(g, instruction->end);
         } else {
-            end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
+            end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false);
         }
         if (want_runtime_safety) {
             add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
             if (instruction->end) {
-                LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+                LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type,
                         array_type->data.array.len, false);
                 add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end);
             }
@@ -4561,7 +4565,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
 
         LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
         LLVMValueRef indices[] = {
-            LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+            LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
             start_val,
         };
         LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
@@ -4663,9 +4667,9 @@ static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, I
 static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable,
         IrInstructionReturnAddress *instruction)
 {
-    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type);
     LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
-    return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
+    return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
 }
 
 static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
@@ -4674,8 +4678,8 @@ static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
 
     ZigType *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
 
-    LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref,
-            &g->builtin_types.entry_i32->type_ref, 1, false);
+    LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, return_type),
+            &g->builtin_types.entry_i32->llvm_type, 1, false);
     g->frame_address_fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type);
     assert(LLVMGetIntrinsicID(g->frame_address_fn_val));
 
@@ -4685,9 +4689,9 @@ static LLVMValueRef get_frame_address_fn_val(CodeGen *g) {
 static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable,
         IrInstructionFrameAddress *instruction)
 {
-    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
+    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->llvm_type);
     LLVMValueRef ptr_val = LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, "");
-    return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->type_ref, "");
+    return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
 }
 
 static LLVMValueRef get_handle_fn_val(CodeGen *g) {
@@ -4706,7 +4710,7 @@ static LLVMValueRef get_handle_fn_val(CodeGen *g) {
 static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
         IrInstructionHandle *instruction)
 {
-    LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_promise->type_ref);
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_promise));
     return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
 }
 
@@ -4786,7 +4790,7 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
         err_val = err_union_handle;
     }
 
-    LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+    LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
     return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
 }
 
@@ -4834,7 +4838,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
         } else {
             err_val = err_union_handle;
         }
-        LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+        LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
         LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
         LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
         LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
@@ -4860,7 +4864,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
 
     ZigType *child_type = wanted_type->data.maybe.child_type;
 
-    if (child_type->zero_bits) {
+    if (!type_has_bits(child_type)) {
         return LLVMConstInt(LLVMInt1Type(), 1, false);
     }
 
@@ -4913,7 +4917,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
         return ir_llvm_value(g, instruction->value);
     }
 
-    LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
+    LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
 
     if (!type_has_bits(payload_type))
         return ok_err_val;
@@ -4991,7 +4995,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
         LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
                 union_type->data.unionation.gen_tag_index, "");
 
-        LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+        LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type),
                 &type_union_field->enum_field->value);
         gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
 
@@ -5001,7 +5005,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
         uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
     }
 
-    LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
+    LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, get_llvm_type(g, ptr_type), "");
     LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
 
     gen_assign_raw(g, field_ptr, ptr_type, value);
@@ -5023,8 +5027,8 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
     for (size_t i = 0; i < field_count; i += 1) {
         LLVMValueRef elem_val = ir_llvm_value(g, instruction->items[i]);
         LLVMValueRef indices[] = {
-            LLVMConstNull(g->builtin_types.entry_usize->type_ref),
-            LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
+            LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
+            LLVMConstInt(g->builtin_types.entry_usize->llvm_type, i, false),
         };
         LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
         gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val);
@@ -5041,7 +5045,7 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
 static LLVMValueRef ir_render_coro_id(CodeGen *g, IrExecutable *executable, IrInstructionCoroId *instruction) {
     LLVMValueRef promise_ptr = ir_llvm_value(g, instruction->promise_ptr);
     LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false);
-    LLVMValueRef null = LLVMConstIntToPtr(LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+    LLVMValueRef null = LLVMConstIntToPtr(LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
             LLVMPointerType(LLVMInt8Type(), 0));
     LLVMValueRef params[] = {
         align_val,
@@ -5140,7 +5144,7 @@ static LLVMValueRef ir_render_coro_promise(CodeGen *g, IrExecutable *executable,
         LLVMConstNull(LLVMInt1Type()),
     };
     LLVMValueRef uncasted_result = LLVMBuildCall(g->builder, get_coro_promise_fn_val(g), params, 3, "");
-    return LLVMBuildBitCast(g->builder, uncasted_result, instruction->base.value.type->type_ref, "");
+    return LLVMBuildBitCast(g->builder, uncasted_result, get_llvm_type(g, instruction->base.value.type), "");
 }
 
 static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, ZigType *fn_type) {
@@ -5161,8 +5165,8 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
         arg_types.append(alloc_fn_arg_types[1]);
     }
     arg_types.append(alloc_fn_arg_types[g->have_err_ret_tracing ? 2 : 1]);
-    arg_types.append(ptr_to_err_code_type->type_ref);
-    arg_types.append(g->builtin_types.entry_usize->type_ref);
+    arg_types.append(get_llvm_type(g, ptr_to_err_code_type));
+    arg_types.append(g->builtin_types.entry_usize->llvm_type);
 
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0),
             arg_types.items, arg_types.length, false);
@@ -5204,7 +5208,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
     next_arg += 1;
     LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
     next_arg += 1;
-    LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,
+    LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->llvm_type,
             get_coro_frame_align_bytes(g), false);
 
     ConstExprValue *zero_array = create_const_str_lit(g, buf_create_from_str(""));
@@ -5219,7 +5223,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
     }
     args.append(allocator_val);
     args.append(undef_slice_zero->global_refs->llvm_global);
-    args.append(LLVMGetUndef(g->builtin_types.entry_u29->type_ref));
+    args.append(LLVMGetUndef(g->builtin_types.entry_u29->llvm_type));
     args.append(coro_size);
     args.append(alignment_val);
     LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, realloc_fn_val, args.items, args.length,
@@ -5299,10 +5303,10 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
 
     // it's a pointer but we need to treat it as an int
     LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
-        LLVMPointerType(g->builtin_types.entry_usize->type_ref, 0), "");
-    LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->type_ref, "");
+        LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
+    LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, "");
     LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, false);
-    return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
+    return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
 }
 
 static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
@@ -5355,15 +5359,15 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst
     ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,
             int_type->data.integral.bit_count + 8);
     // aabbcc
-    LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, "");
+    LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), "");
     // 00aabbcc
     LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap);
     LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, "");
     // ccbbaa00
     LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,
-            LLVMConstInt(extended_type->type_ref, 8, false), "");
+            LLVMConstInt(get_llvm_type(g, extended_type), 8, false), "");
     // 00ccbbaa
-    return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
+    return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, int_type), "");
 }
 
 static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) {
@@ -5383,7 +5387,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
     assert(instruction->tmp_ptr);
     LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
     LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
-            LLVMPointerType(instruction->vector->value.type->type_ref, 0), "");
+            LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
     gen_store_untyped(g, vector, casted_ptr, 0, false);
     return instruction->tmp_ptr;
 }
@@ -5396,7 +5400,7 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
     assert(!handle_is_ptr(vector_type));
     LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
     LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
-            LLVMPointerType(vector_type->type_ref, 0), "");
+            LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
     return gen_load_untyped(g, casted_ptr, 0, false, "");
 }
 
@@ -5735,15 +5739,15 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
     if (el_type == LLVMArrayTypeKind) {
         ZigType *usize = g->builtin_types.entry_usize;
         LLVMValueRef indices[] = {
-            LLVMConstNull(usize->type_ref),
-            LLVMConstInt(usize->type_ref, index, false),
+            LLVMConstNull(usize->llvm_type),
+            LLVMConstInt(usize->llvm_type, index, false),
         };
         return LLVMConstInBoundsGEP(base_ptr, indices, 2);
     } else if (el_type == LLVMStructTypeKind) {
         ZigType *u32 = g->builtin_types.entry_u32;
         LLVMValueRef indices[] = {
-            LLVMConstNull(u32->type_ref),
-            LLVMConstInt(u32->type_ref, index, false),
+            LLVMConstNull(get_llvm_type(g, u32)),
+            LLVMConstInt(get_llvm_type(g, u32), index, false),
         };
         return LLVMConstInBoundsGEP(base_ptr, indices, 2);
     } else {
@@ -5758,8 +5762,8 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
 
     ZigType *u32 = g->builtin_types.entry_u32;
     LLVMValueRef indices[] = {
-        LLVMConstNull(u32->type_ref),
-        LLVMConstInt(u32->type_ref, field_index, false),
+        LLVMConstNull(get_llvm_type(g, u32)),
+        LLVMConstInt(get_llvm_type(g, u32), field_index, false),
     };
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
@@ -5770,8 +5774,8 @@ static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExpr
 
     ZigType *u32 = g->builtin_types.entry_u32;
     LLVMValueRef indices[] = {
-        LLVMConstNull(u32->type_ref),
-        LLVMConstInt(u32->type_ref, err_union_err_index, false),
+        LLVMConstNull(get_llvm_type(g, u32)),
+        LLVMConstInt(get_llvm_type(g, u32), err_union_err_index, false),
     };
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
@@ -5782,8 +5786,8 @@ static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstE
 
     ZigType *u32 = g->builtin_types.entry_u32;
     LLVMValueRef indices[] = {
-        LLVMConstNull(u32->type_ref),
-        LLVMConstInt(u32->type_ref, err_union_payload_index, false),
+        LLVMConstNull(get_llvm_type(g, u32)),
+        LLVMConstInt(get_llvm_type(g, u32), err_union_payload_index, false),
     };
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
@@ -5794,8 +5798,8 @@ static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstEx
 
     ZigType *u32 = g->builtin_types.entry_u32;
     LLVMValueRef indices[] = {
-        LLVMConstNull(u32->type_ref),
-        LLVMConstInt(u32->type_ref, maybe_child_index, false),
+        LLVMConstNull(get_llvm_type(g, u32)),
+        LLVMConstInt(get_llvm_type(g, u32), maybe_child_index, false),
     };
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
@@ -5806,8 +5810,8 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un
 
     ZigType *u32 = g->builtin_types.entry_u32;
     LLVMValueRef indices[] = {
-        LLVMConstNull(u32->type_ref),
-        LLVMConstInt(u32->type_ref, 0, false), // TODO test const union with more aligned tag type than payload
+        LLVMConstNull(get_llvm_type(g, u32)),
+        LLVMConstInt(get_llvm_type(g, u32), 0, false), // TODO test const union with more aligned tag type than payload
     };
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
@@ -5823,7 +5827,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
     }
 
     ZigType *type_entry = const_val->type;
-    assert(!type_entry->zero_bits);
+    assert(type_has_bits(type_entry));
     switch (type_entry->id) {
         case ZigTypeIdInvalid:
         case ZigTypeIdMetaType:
@@ -5866,7 +5870,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
         case ZigTypeIdPromise:
             {
                 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
-                LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
+                LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type);
                 return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);
             }
         case ZigTypeIdArray: {
@@ -5933,8 +5937,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
 
 // We have this because union constants can't be represented by the official union type,
 // and this property bubbles up in whatever aggregate type contains a union constant
-static bool is_llvm_value_unnamed_type(ZigType *type_entry, LLVMValueRef val) {
-    return LLVMTypeOf(val) != type_entry->type_ref;
+static bool is_llvm_value_unnamed_type(CodeGen *g, ZigType *type_entry, LLVMValueRef val) {
+    return LLVMTypeOf(val) != get_llvm_type(g, type_entry);
 }
 
 static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) {
@@ -5948,7 +5952,8 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee;
                 render_const_val(g, pointee, "");
                 render_const_val_global(g, pointee, "");
-                const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global, const_val->type->type_ref);
+                const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global,
+                        get_llvm_type(g, const_val->type));
                 return const_val->global_refs->llvm_value;
             }
         case ConstPtrSpecialBaseArray:
@@ -5959,13 +5964,13 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 if (!type_has_bits(array_const_val->type)) {
                     // make this a null pointer
                     ZigType *usize = g->builtin_types.entry_usize;
-                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
-                            const_val->type->type_ref);
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+                            get_llvm_type(g, const_val->type));
                     return const_val->global_refs->llvm_value;
                 }
                 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
                 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index);
-                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type));
                 const_val->global_refs->llvm_value = ptr_val;
                 return ptr_val;
             }
@@ -5977,15 +5982,15 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 if (!type_has_bits(struct_const_val->type)) {
                     // make this a null pointer
                     ZigType *usize = g->builtin_types.entry_usize;
-                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
-                            const_val->type->type_ref);
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+                            get_llvm_type(g, const_val->type));
                     return const_val->global_refs->llvm_value;
                 }
                 size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index;
                 size_t gen_field_index = struct_const_val->type->data.structure.fields[src_field_index].gen_index;
                 LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val,
                         gen_field_index);
-                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type));
                 const_val->global_refs->llvm_value = ptr_val;
                 return ptr_val;
             }
@@ -5997,12 +6002,12 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 if (!type_has_bits(err_union_const_val->type)) {
                     // make this a null pointer
                     ZigType *usize = g->builtin_types.entry_usize;
-                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
-                            const_val->type->type_ref);
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+                            get_llvm_type(g, const_val->type));
                     return const_val->global_refs->llvm_value;
                 }
                 LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val);
-                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type));
                 const_val->global_refs->llvm_value = ptr_val;
                 return ptr_val;
             }
@@ -6011,15 +6016,15 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 assert(const_val->global_refs != nullptr);
                 ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val;
                 assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
-                if (err_union_const_val->type->zero_bits) {
+                if (!type_has_bits(err_union_const_val->type)) {
                     // make this a null pointer
                     ZigType *usize = g->builtin_types.entry_usize;
-                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
-                            const_val->type->type_ref);
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+                            get_llvm_type(g, const_val->type));
                     return const_val->global_refs->llvm_value;
                 }
                 LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val);
-                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type));
                 const_val->global_refs->llvm_value = ptr_val;
                 return ptr_val;
             }
@@ -6028,15 +6033,15 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 assert(const_val->global_refs != nullptr);
                 ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val;
                 assert(optional_const_val->type->id == ZigTypeIdOptional);
-                if (optional_const_val->type->zero_bits) {
+                if (!type_has_bits(optional_const_val->type)) {
                     // make this a null pointer
                     ZigType *usize = g->builtin_types.entry_usize;
-                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
-                            const_val->type->type_ref);
+                    const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
+                            get_llvm_type(g, const_val->type));
                     return const_val->global_refs->llvm_value;
                 }
                 LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val);
-                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+                LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, get_llvm_type(g, const_val->type));
                 const_val->global_refs->llvm_value = ptr_val;
                 return ptr_val;
             }
@@ -6046,50 +6051,51 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
                 uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr;
                 ZigType *usize = g->builtin_types.entry_usize;
                 const_val->global_refs->llvm_value = LLVMConstIntToPtr(
-                        LLVMConstInt(usize->type_ref, addr_value, false), const_val->type->type_ref);
+                        LLVMConstInt(usize->llvm_type, addr_value, false), get_llvm_type(g, const_val->type));
                 return const_val->global_refs->llvm_value;
             }
         case ConstPtrSpecialFunction:
-            return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
+            return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry),
+                    get_llvm_type(g, const_val->type));
         case ConstPtrSpecialNull:
-            return LLVMConstNull(const_val->type->type_ref);
+            return LLVMConstNull(get_llvm_type(g, const_val->type));
     }
     zig_unreachable();
 }
 
 static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) {
     uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value;
-    return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false);
+    return LLVMConstInt(get_llvm_type(g, g->builtin_types.entry_global_error_set), value, false);
 }
 
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
     Error err;
 
     ZigType *type_entry = const_val->type;
-    assert(!type_entry->zero_bits);
+    assert(type_has_bits(type_entry));
 
     switch (const_val->special) {
         case ConstValSpecialRuntime:
             zig_unreachable();
         case ConstValSpecialUndef:
-            return LLVMGetUndef(type_entry->type_ref);
+            return LLVMGetUndef(get_llvm_type(g, type_entry));
         case ConstValSpecialStatic:
             break;
     }
 
     switch (type_entry->id) {
         case ZigTypeIdInt:
-            return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
+            return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint);
         case ZigTypeIdErrorSet:
             return gen_const_val_err_set(g, const_val, name);
         case ZigTypeIdFloat:
             switch (type_entry->data.floating.bit_count) {
                 case 16:
-                    return LLVMConstReal(type_entry->type_ref, zig_f16_to_double(const_val->data.x_f16));
+                    return LLVMConstReal(get_llvm_type(g, type_entry), zig_f16_to_double(const_val->data.x_f16));
                 case 32:
-                    return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
+                    return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32);
                 case 64:
-                    return LLVMConstReal(type_entry->type_ref, const_val->data.x_f64);
+                    return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f64);
                 case 128:
                     {
                         // TODO make sure this is correct on big endian targets too
@@ -6097,7 +6103,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                         memcpy(buf, &const_val->data.x_f128, 16);
                         LLVMValueRef as_int = LLVMConstIntOfArbitraryPrecision(LLVMInt128Type(), 2,
                                 (uint64_t*)buf);
-                        return LLVMConstBitCast(as_int, type_entry->type_ref);
+                        return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry));
                     }
                 default:
                     zig_unreachable();
@@ -6125,9 +6131,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                         child_val = gen_const_val(g, const_val->data.x_optional, "");
                         maybe_val = LLVMConstAllOnes(LLVMInt1Type());
 
-                        make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
+                        make_unnamed_struct = is_llvm_value_unnamed_type(g, const_val->type, child_val);
                     } else {
-                        child_val = LLVMGetUndef(child_type->type_ref);
+                        child_val = LLVMGetUndef(get_llvm_type(g, child_type));
                         maybe_val = LLVMConstNull(LLVMInt1Type());
 
                         make_unnamed_struct = false;
@@ -6139,7 +6145,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     if (make_unnamed_struct) {
                         return LLVMConstStruct(fields, 2, false);
                     } else {
-                        return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                        return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
                     }
                 }
             }
@@ -6168,10 +6174,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                             ConstExprValue *field_val = &const_val->data.x_struct.fields[src_field_index];
                             LLVMValueRef val = gen_const_val(g, field_val, "");
                             fields[type_struct_field->gen_index] = val;
-                            make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
+                            make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
                         } else {
                             bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
-                            LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,
+                            LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry),
                                     (unsigned)type_struct_field->gen_index);
                             LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
                             size_t used_bits = 0;
@@ -6216,14 +6222,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
 
                         LLVMValueRef val = gen_const_val(g, field_val, "");
                         fields[type_struct_field->gen_index] = val;
-                        make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
+                        make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
                     }
                 }
                 if (make_unnamed_struct) {
                     return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count,
                         type_entry->data.structure.layout == ContainerLayoutPacked);
                 } else {
-                    return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
+                    return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, type_entry->data.structure.gen_field_count);
                 }
             }
         case ZigTypeIdArray:
@@ -6231,16 +6237,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                 uint64_t len = type_entry->data.array.len;
                 switch (const_val->data.x_array.special) {
                     case ConstArraySpecialUndef:
-                        return LLVMGetUndef(type_entry->type_ref);
+                        return LLVMGetUndef(get_llvm_type(g, type_entry));
                     case ConstArraySpecialNone: {
                         LLVMValueRef *values = allocate<LLVMValueRef>(len);
-                        LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref;
+                        LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type);
                         bool make_unnamed_struct = false;
                         for (uint64_t i = 0; i < len; i += 1) {
                             ConstExprValue *elem_value = &const_val->data.x_array.data.s_none.elements[i];
                             LLVMValueRef val = gen_const_val(g, elem_value, "");
                             values[i] = val;
-                            make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
+                            make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val);
                         }
                         if (make_unnamed_struct) {
                             return LLVMConstStruct(values, len, true);
@@ -6259,7 +6265,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
             uint32_t len = type_entry->data.vector.len;
             switch (const_val->data.x_array.special) {
                 case ConstArraySpecialUndef:
-                    return LLVMGetUndef(type_entry->type_ref);
+                    return LLVMGetUndef(get_llvm_type(g, type_entry));
                 case ConstArraySpecialNone: {
                     LLVMValueRef *values = allocate<LLVMValueRef>(len);
                     for (uint64_t i = 0; i < len; i += 1) {
@@ -6273,7 +6279,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     assert(buf_len(buf) == len);
                     LLVMValueRef *values = allocate<LLVMValueRef>(len);
                     for (uint64_t i = 0; i < len; i += 1) {
-                        values[i] = LLVMConstInt(g->builtin_types.entry_u8->type_ref, buf_ptr(buf)[i], false);
+                        values[i] = LLVMConstInt(g->builtin_types.entry_u8->llvm_type, buf_ptr(buf)[i], false);
                     }
                     return LLVMConstVector(values, len);
                 }
@@ -6282,13 +6288,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
         }
         case ZigTypeIdUnion:
             {
-                LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;
+                BREAKPOINT; // TODO rework this logic to take into account the new layout
+
+                // Force type_entry->data.unionation.union_llvm_type to get resolved
+                (void)get_llvm_type(g, type_entry);
+
+                LLVMTypeRef union_type_ref = type_entry->data.unionation.union_llvm_type;
+                assert(union_type_ref != nullptr);
 
                 if (type_entry->data.unionation.gen_field_count == 0) {
                     if (type_entry->data.unionation.tag_type == nullptr) {
                         return nullptr;
                     } else {
-                        return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
+                        return bigint_to_llvm_const(get_llvm_type(g, type_entry->data.unionation.tag_type),
                             &const_val->data.x_union.tag);
                     }
                 }
@@ -6298,15 +6310,16 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                 ConstExprValue *payload_value = const_val->data.x_union.payload;
                 if (payload_value == nullptr || !type_has_bits(payload_value->type)) {
                     if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
-                        return LLVMGetUndef(type_entry->type_ref);
+                        return LLVMGetUndef(get_llvm_type(g, type_entry));
 
                     union_value_ref = LLVMGetUndef(union_type_ref);
                     make_unnamed_struct = false;
                 } else {
-                    uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
-                    uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
+                    uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
+                            get_llvm_type(g, payload_value->type));
+                    uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes;
                     LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, "");
-                    make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
+                    make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) ||
                         payload_value->type != type_entry->data.unionation.most_aligned_union_member;
 
                     {
@@ -6329,7 +6342,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     }
                 }
 
-                LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
+                LLVMValueRef tag_value = bigint_to_llvm_const(
+                        get_llvm_type(g, type_entry->data.unionation.tag_type),
                         &const_val->data.x_union.tag);
 
                 LLVMValueRef fields[3];
@@ -6341,7 +6355,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1);
                     uint64_t end_offset = last_field_offset +
                         LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1]));
-                    uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
+                    uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, get_llvm_type(g, type_entry));
                     unsigned pad_sz = expected_sz - end_offset;
                     if (pad_sz != 0) {
                         fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz));
@@ -6351,21 +6365,21 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     assert(actual_sz == expected_sz);
                     return result;
                 } else {
-                    return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                    return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
                 }
 
             }
 
         case ZigTypeIdEnum:
-            return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
+            return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_enum_tag);
         case ZigTypeIdFn:
             if (const_val->data.x_ptr.special == ConstPtrSpecialFunction) {
                 assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
                 return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
             } else if (const_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
-                LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
+                LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
                 uint64_t addr = const_val->data.x_ptr.data.hard_coded_addr.addr;
-                return LLVMConstIntToPtr(LLVMConstInt(usize_type_ref, addr, false), type_entry->type_ref);
+                return LLVMConstIntToPtr(LLVMConstInt(usize_type_ref, addr, false), get_llvm_type(g, type_entry));
             } else {
                 zig_unreachable();
             }
@@ -6379,7 +6393,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     assert(type_has_bits(err_set_type));
                     ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
                     uint64_t value = (err_set == nullptr) ? 0 : err_set->value;
-                    return LLVMConstInt(g->err_tag_type->type_ref, value, false);
+                    return LLVMConstInt(get_llvm_type(g, g->err_tag_type), value, false);
                 } else if (!type_has_bits(err_set_type)) {
                     assert(type_has_bits(payload_type));
                     return gen_const_val(g, const_val->data.x_err_union.payload, "");
@@ -6389,17 +6403,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                     bool make_unnamed_struct;
                     ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
                     if (err_set != nullptr) {
-                        err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false);
-                        err_payload_value = LLVMConstNull(payload_type->type_ref);
+                        err_tag_value = LLVMConstInt(get_llvm_type(g, g->err_tag_type), err_set->value, false);
+                        err_payload_value = LLVMConstNull(get_llvm_type(g, payload_type));
                         make_unnamed_struct = false;
                     } else {
-                        err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
+                        err_tag_value = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
                         ConstExprValue *payload_val = const_val->data.x_err_union.payload;
                         err_payload_value = gen_const_val(g, payload_val, "");
-                        make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
+                        make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);
                     }
                     if (make_unnamed_struct) {
-                        uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, type_entry->type_ref, 1);
+                        uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, get_llvm_type(g, type_entry), 1);
                         uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value));
                         unsigned pad_sz = payload_off - err_sz;
                         if (pad_sz == 0) {
@@ -6421,7 +6435,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                             err_tag_value,
                             err_payload_value,
                         };
-                        return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                        return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
                     }
                 }
             }
@@ -6460,7 +6474,8 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const
         const_val->global_refs = allocate<ConstGlobalRefs>(1);
 
     if (!const_val->global_refs->llvm_global) {
-        LLVMTypeRef type_ref = const_val->global_refs->llvm_value ? LLVMTypeOf(const_val->global_refs->llvm_value) : const_val->type->type_ref;
+        LLVMTypeRef type_ref = const_val->global_refs->llvm_value ?
+            LLVMTypeOf(const_val->global_refs->llvm_value) : get_llvm_type(g, const_val->type);
         LLVMValueRef global_value = LLVMAddGlobal(g->module, type_ref, name);
         LLVMSetLinkage(global_value, LLVMInternalLinkage);
         LLVMSetGlobalConstant(global_value, true);
@@ -6486,7 +6501,7 @@ static void generate_error_name_table(CodeGen *g) {
     ZigType *str_type = get_slice_type(g, u8_ptr_type);
 
     LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
-    values[0] = LLVMGetUndef(str_type->type_ref);
+    values[0] = LLVMGetUndef(get_llvm_type(g, str_type));
     for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
         ErrorTableEntry *err_entry = g->errors_by_index.at(i);
         Buf *name = &err_entry->name;
@@ -6502,13 +6517,13 @@ static void generate_error_name_table(CodeGen *g) {
         LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init)));
 
         LLVMValueRef fields[] = {
-            LLVMConstBitCast(str_global, u8_ptr_type->type_ref),
-            LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false),
+            LLVMConstBitCast(str_global, get_llvm_type(g, u8_ptr_type)),
+            LLVMConstInt(g->builtin_types.entry_usize->llvm_type, buf_len(name), false),
         };
-        values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
+        values[i] = LLVMConstNamedStruct(get_llvm_type(g, str_type), fields, 2);
     }
 
-    LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->errors_by_index.length);
+    LLVMValueRef err_name_table_init = LLVMConstArray(get_llvm_type(g, str_type), values, (unsigned)g->errors_by_index.length);
 
     g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
             buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
@@ -6547,7 +6562,7 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
     ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
         buf_ptr(&var->name), import->data.structure.root_struct->di_file,
         (unsigned)(var->decl_node->line + 1),
-        type_entry->di_type, is_local_to_unit);
+        get_llvm_di_type(g, type_entry), is_local_to_unit);
 
     // TODO ^^ make an actual global variable
 }
@@ -6588,28 +6603,6 @@ static LLVMLinkage var_linkage_to_llvm(VarLinkage var_linkage) {
 static void do_code_gen(CodeGen *g) {
     assert(!g->errors.length);
 
-    {
-        // create debug type for error sets
-        assert(g->err_enumerators.length == g->errors_by_index.length);
-        uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
-        uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref);
-        ZigLLVMDIFile *err_set_di_file = nullptr;
-        ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
-                ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name),
-                err_set_di_file, 0,
-                tag_debug_size_in_bits,
-                tag_debug_align_in_bits,
-                g->err_enumerators.items, g->err_enumerators.length,
-                g->err_tag_type->di_type, "");
-        ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type);
-        g->builtin_types.entry_global_error_set->di_type = err_set_di_type;
-
-        for (size_t i = 0; i < g->error_di_types.length; i += 1) {
-            ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i);
-            *di_type_ptr = err_set_di_type;
-        }
-    }
-
     generate_error_name_table(g);
 
     // Generate module level variables
@@ -6646,7 +6639,7 @@ static void do_code_gen(CodeGen *g) {
                 bits_needed = 8;
             }
             ZigType *var_type = get_int_type(g, const_val->data.x_bigint.is_negative, bits_needed);
-            LLVMValueRef init_val = bigint_to_llvm_const(var_type->type_ref, &const_val->data.x_bigint);
+            LLVMValueRef init_val = bigint_to_llvm_const(get_llvm_type(g, var_type), &const_val->data.x_bigint);
             gen_global_var(g, var, init_val, var_type);
             continue;
         }
@@ -6660,9 +6653,10 @@ static void do_code_gen(CodeGen *g) {
         if (var->linkage == VarLinkageExternal) {
             LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name));
             if (existing_llvm_var) {
-                global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0));
+                global_value = LLVMConstBitCast(existing_llvm_var,
+                        LLVMPointerType(get_llvm_type(g, var->var_type), 0));
             } else {
-                global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
+                global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), buf_ptr(&var->name));
                 // TODO debug info for the extern variable
 
                 LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
@@ -6834,7 +6828,7 @@ static void do_code_gen(CodeGen *g) {
 
                 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
                         buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1),
-                        var->var_type->di_type, !g->strip_debug_symbols, 0);
+                        get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
 
             } else if (is_c_abi) {
                 fn_walk_var.data.vars.var = var;
@@ -6859,7 +6853,7 @@ static void do_code_gen(CodeGen *g) {
                     var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
                             buf_ptr(&var->name), import->data.structure.root_struct->di_file,
                             (unsigned)(var->decl_node->line + 1),
-                            gen_type->di_type, !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
+                            get_llvm_di_type(g, gen_type), !g->strip_debug_symbols, 0, (unsigned)(var->gen_arg_index + 1));
                 }
 
             }
@@ -6870,7 +6864,7 @@ static void do_code_gen(CodeGen *g) {
             ZigType *usize = g->builtin_types.entry_usize;
             size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
             LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
-            gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
+            gen_store_untyped(g, LLVMConstNull(usize->llvm_type), index_field_ptr, 0, false);
 
             size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
             LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
@@ -6878,7 +6872,7 @@ static void do_code_gen(CodeGen *g) {
             ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
             size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
             LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
-            LLVMValueRef zero = LLVMConstNull(usize->type_ref);
+            LLVMValueRef zero = LLVMConstNull(usize->llvm_type);
             LLVMValueRef indices[] = {zero, zero};
             LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
                     indices, 2, "");
@@ -6887,7 +6881,7 @@ static void do_code_gen(CodeGen *g) {
 
             size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
             LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
-            gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
+            gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
         }
 
         // create debug variable declarations for parameters
@@ -6997,50 +6991,60 @@ static const GlobalLinkageValue global_linkage_values[] = {
     {GlobalLinkageIdLinkOnce, "LinkOnce"},
 };
 
+static void add_fp_entry(CodeGen *g, const char *name, uint32_t bit_count, LLVMTypeRef type_ref,
+        ZigType **field)
+{
+    ZigType *entry = new_type_table_entry(ZigTypeIdFloat);
+    entry->llvm_type = type_ref;
+    entry->size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->llvm_type);
+    entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
+    entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
+    buf_init_from_str(&entry->name, name);
+    entry->data.floating.bit_count = bit_count;
+
+    entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+            entry->size_in_bits, ZigLLVMEncoding_DW_ATE_float());
+    *field = entry;
+    g->primitive_type_table.put(&entry->name, entry);
+}
+
 static void define_builtin_types(CodeGen *g) {
     {
         // if this type is anywhere in the AST, we should never hit codegen.
         ZigType *entry = new_type_table_entry(ZigTypeIdInvalid);
         buf_init_from_str(&entry->name, "(invalid)");
-        entry->zero_bits = true;
         g->builtin_types.entry_invalid = entry;
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdComptimeFloat);
         buf_init_from_str(&entry->name, "comptime_float");
-        entry->zero_bits = true;
         g->builtin_types.entry_num_lit_float = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdComptimeInt);
         buf_init_from_str(&entry->name, "comptime_int");
-        entry->zero_bits = true;
         g->builtin_types.entry_num_lit_int = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral);
         buf_init_from_str(&entry->name, "(enum literal)");
-        entry->zero_bits = true;
         g->builtin_types.entry_enum_literal = entry;
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);
         buf_init_from_str(&entry->name, "(undefined)");
-        entry->zero_bits = true;
         g->builtin_types.entry_undef = entry;
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdNull);
         buf_init_from_str(&entry->name, "(null)");
-        entry->zero_bits = true;
         g->builtin_types.entry_null = entry;
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdArgTuple);
         buf_init_from_str(&entry->name, "(args)");
-        entry->zero_bits = true;
         g->builtin_types.entry_arg_tuple = entry;
     }
 
@@ -7050,14 +7054,15 @@ static void define_builtin_types(CodeGen *g) {
         bool is_signed = info->is_signed;
 
         ZigType *entry = new_type_table_entry(ZigTypeIdInt);
-        entry->type_ref = LLVMIntType(size_in_bits);
+        entry->llvm_type = LLVMIntType(size_in_bits);
+        entry->size_in_bits = size_in_bits;
+        entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
+        entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
 
         buf_init_from_str(&entry->name, info->name);
 
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                debug_size_in_bits,
-                is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned());
+        entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+                size_in_bits, is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned());
         entry->data.integral.is_signed = is_signed;
         entry->data.integral.bit_count = size_in_bits;
         g->primitive_type_table.put(&entry->name, entry);
@@ -7067,12 +7072,13 @@ static void define_builtin_types(CodeGen *g) {
 
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdBool);
-        entry->type_ref = LLVMInt1Type();
+        entry->llvm_type = LLVMInt1Type();
+        entry->size_in_bits = 1;
+        entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
+        entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
         buf_init_from_str(&entry->name, "bool");
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                debug_size_in_bits,
-                ZigLLVMEncoding_DW_ATE_boolean());
+        entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+                entry->size_in_bits, ZigLLVMEncoding_DW_ATE_boolean());
         g->builtin_types.entry_bool = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
@@ -7081,7 +7087,10 @@ static void define_builtin_types(CodeGen *g) {
         bool is_signed = is_signed_list[sign_i];
 
         ZigType *entry = new_type_table_entry(ZigTypeIdInt);
-        entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
+        entry->llvm_type = LLVMIntType(g->pointer_size_bytes * 8);
+        entry->size_in_bits = g->pointer_size_bytes * 8;
+        entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
+        entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
 
         const char u_or_i = is_signed ? 'i' : 'u';
         buf_resize(&entry->name, 0);
@@ -7090,9 +7099,8 @@ static void define_builtin_types(CodeGen *g) {
         entry->data.integral.is_signed = is_signed;
         entry->data.integral.bit_count = g->pointer_size_bytes * 8;
 
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                debug_size_in_bits,
+        entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+                entry->size_in_bits,
                 is_signed ? ZigLLVMEncoding_DW_ATE_signed() : ZigLLVMEncoding_DW_ATE_unsigned());
         g->primitive_type_table.put(&entry->name, entry);
 
@@ -7103,23 +7111,6 @@ static void define_builtin_types(CodeGen *g) {
         }
     }
 
-    auto add_fp_entry = [] (CodeGen *g,
-                            const char *name,
-                            uint32_t bit_count,
-                            LLVMTypeRef type_ref,
-                            ZigType **field) {
-        ZigType *entry = new_type_table_entry(ZigTypeIdFloat);
-        entry->type_ref = type_ref;
-        buf_init_from_str(&entry->name, name);
-        entry->data.floating.bit_count = bit_count;
-
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
-        entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                debug_size_in_bits,
-                ZigLLVMEncoding_DW_ATE_float());
-        *field = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    };
     add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
     add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
     add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
@@ -7128,10 +7119,9 @@ static void define_builtin_types(CodeGen *g) {
 
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdVoid);
-        entry->type_ref = LLVMVoidType();
-        entry->zero_bits = true;
+        entry->llvm_type = LLVMVoidType();
         buf_init_from_str(&entry->name, "void");
-        entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+        entry->llvm_di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
                 0,
                 ZigLLVMEncoding_DW_ATE_unsigned());
         g->builtin_types.entry_void = entry;
@@ -7139,17 +7129,15 @@ static void define_builtin_types(CodeGen *g) {
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdUnreachable);
-        entry->type_ref = LLVMVoidType();
-        entry->zero_bits = true;
+        entry->llvm_type = LLVMVoidType();
         buf_init_from_str(&entry->name, "noreturn");
-        entry->di_type = g->builtin_types.entry_void->di_type;
+        entry->llvm_di_type = g->builtin_types.entry_void->llvm_di_type;
         g->builtin_types.entry_unreachable = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
     {
         ZigType *entry = new_type_table_entry(ZigTypeIdMetaType);
         buf_init_from_str(&entry->name, "type");
-        entry->zero_bits = true;
         g->builtin_types.entry_type = entry;
         g->primitive_type_table.put(&entry->name, entry);
     }
@@ -7174,19 +7162,15 @@ static void define_builtin_types(CodeGen *g) {
         buf_init_from_str(&entry->name, "anyerror");
         entry->data.error_set.err_count = UINT32_MAX;
 
-        // TODO allow overriding this type and keep track of max value and emit an
-        // error if there are too many errors declared
+        // TODO https://github.com/ziglang/zig/issues/786
         g->err_tag_type = g->builtin_types.entry_u16;
 
-        g->builtin_types.entry_global_error_set = entry;
-        entry->type_ref = g->err_tag_type->type_ref;
+        entry->size_in_bits = g->err_tag_type->size_in_bits;
+        entry->abi_align = g->err_tag_type->abi_align;
+        entry->abi_size = g->err_tag_type->abi_size;
 
-        entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
-            ZigLLVMTag_DW_enumeration_type(), "anyerror",
-            ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0);
+        g->builtin_types.entry_global_error_set = entry;
 
-        // reserve index 0 to indicate no error
-        g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0));
         g->errors_by_index.append(nullptr);
 
         g->primitive_type_table.put(&entry->name, entry);
@@ -7194,6 +7178,9 @@ static void define_builtin_types(CodeGen *g) {
     {
         ZigType *entry = get_promise_type(g, nullptr);
         g->primitive_type_table.put(&entry->name, entry);
+        entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
+        entry->abi_align = g->builtin_types.entry_usize->abi_align;
+        entry->abi_size = g->builtin_types.entry_usize->abi_size;
     }
 }
 
src/ir.cpp
@@ -6842,6 +6842,9 @@ static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigTyp
     assert(set2->id == ZigTypeIdErrorSet);
 
     ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
+    err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits;
+    err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align;
+    err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size;
     buf_resize(&err_set_type->name, 0);
     buf_appendf(&err_set_type->name, "error{");
 
@@ -6857,8 +6860,6 @@ static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigTyp
         }
     }
 
-    err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
-    err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
     err_set_type->data.error_set.err_count = count;
     err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(count);
 
@@ -6883,8 +6884,6 @@ static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigTyp
 
     buf_appendf(&err_set_type->name, "}");
 
-    g->error_di_types.append(&err_set_type->di_type);
-
     return err_set_type;
 
 }
@@ -6895,13 +6894,12 @@ static ZigType *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstN
     ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
     buf_resize(&err_set_type->name, 0);
     buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name));
-    err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
-    err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
+    err_set_type->size_in_bits = g->builtin_types.entry_global_error_set->size_in_bits;
+    err_set_type->abi_align = g->builtin_types.entry_global_error_set->abi_align;
+    err_set_type->abi_size = g->builtin_types.entry_global_error_set->abi_size;
     err_set_type->data.error_set.err_count = 1;
     err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
 
-    g->error_di_types.append(&err_set_type->di_type);
-
     err_set_type->data.error_set.errors[0] = err_entry;
 
     return err_set_type;
@@ -6917,9 +6915,9 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
     ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
     buf_init_from_buf(&err_set_type->name, type_name);
     err_set_type->data.error_set.err_count = err_count;
-    err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref;
-    err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type;
-    irb->codegen->error_di_types.append(&err_set_type->di_type);
+    err_set_type->size_in_bits = irb->codegen->builtin_types.entry_global_error_set->size_in_bits;
+    err_set_type->abi_align = irb->codegen->builtin_types.entry_global_error_set->abi_align;
+    err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size;
     err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
 
     ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
@@ -6940,8 +6938,6 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
             assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count));
             err->value = error_value_count;
             irb->codegen->errors_by_index.append(err);
-            irb->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(irb->codegen->dbuilder,
-                buf_ptr(err_name), error_value_count));
         }
         err_set_type->data.error_set.errors[i] = err;
 
@@ -8947,16 +8943,16 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
     }
     free(errors);
 
-    err_set_type->type_ref = ira->codegen->builtin_types.entry_global_error_set->type_ref;
-    err_set_type->di_type = ira->codegen->builtin_types.entry_global_error_set->di_type;
     err_set_type->data.error_set.err_count = intersection_list.length;
     err_set_type->data.error_set.errors = intersection_list.items;
-    err_set_type->zero_bits = intersection_list.length == 0;
+    if (intersection_list.length != 0) {
+        err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits;
+        err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align;
+        err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size;
+    }
 
     buf_appendf(&err_set_type->name, "}");
 
-    ira->codegen->error_di_types.append(&err_set_type->di_type);
-
     return err_set_type;
 }
 
@@ -14855,7 +14851,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
     ZigType *type_entry = ir_resolve_type(ira, value);
     if (type_is_invalid(type_entry))
         return ira->codegen->invalid_instruction;
-    if ((err = ensure_complete_type(ira->codegen, type_entry)))
+    if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown)))
         return ira->codegen->invalid_instruction;
 
     switch (type_entry->id) {
@@ -16051,8 +16047,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
                     assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
                     err_entry->value = error_value_count;
                     ira->codegen->errors_by_index.append(err_entry);
-                    ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder,
-                        buf_ptr(field_name), error_value_count));
                     ira->codegen->error_table.put(field_name, err_entry);
                 }
                 if (err_entry->set_with_only_this_in_it == nullptr) {
@@ -17873,7 +17867,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira,
         return nullptr;
     }
 
-    *byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index);
+    *byte_offset = field->offset;
     return field;
 }
 
@@ -18726,7 +18720,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
                     if (!type_has_bits(struct_field->type_entry)) {
                         inner_fields[1].data.x_optional = nullptr;
                     } else {
-                        size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index);
+                        size_t byte_offset = struct_field->offset;
                         inner_fields[1].data.x_optional = create_const_vals(1);
                         inner_fields[1].data.x_optional->special = ConstValSpecialStatic;
                         inner_fields[1].data.x_optional->type = ira->codegen->builtin_types.entry_num_lit_int;
@@ -21425,12 +21419,11 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
                 case ContainerLayoutExtern: {
                     size_t src_field_count = val->type->data.structure.src_field_count;
                     for (size_t field_i = 0; field_i < src_field_count; field_i += 1) {
-                        TypeStructField *type_field = &val->type->data.structure.fields[field_i];
-                        if (type_field->gen_index == SIZE_MAX)
+                        TypeStructField *struct_field = &val->type->data.structure.fields[field_i];
+                        if (struct_field->gen_index == SIZE_MAX)
                             continue;
                         ConstExprValue *field_val = &val->data.x_struct.fields[field_i];
-                        size_t offset = LLVMOffsetOfElement(codegen->target_data_ref, val->type->type_ref,
-                                type_field->gen_index);
+                        size_t offset = struct_field->offset;
                         buf_write_value_bytes(codegen, buf + offset, field_val);
                     }
                     return;
@@ -21446,10 +21439,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
                     size_t child_buf_len = 16;
                     uint8_t *child_buf = child_buf_prealloc;
                     while (gen_i < gen_field_count) {
-                        LLVMTypeRef gen_llvm_int_type = LLVMStructGetTypeAtIndex(val->type->type_ref,
-                                    (unsigned)gen_i);
-                        size_t big_int_bit_count = LLVMGetIntTypeWidth(gen_llvm_int_type);
-                        size_t big_int_byte_count = big_int_bit_count / 8;
+                        size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i];
                         if (big_int_byte_count > child_buf_len) {
                             child_buf = allocate_nonzero<uint8_t>(big_int_byte_count);
                             child_buf_len = big_int_byte_count;
@@ -21485,7 +21475,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
                             }
                             src_i += 1;
                         }
-                        bigint_write_twos_complement(&big_int, buf + offset, big_int_bit_count, is_big_endian);
+                        bigint_write_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian);
                         offset += big_int_byte_count;
                         gen_i += 1;
                     }
@@ -21606,12 +21596,11 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
                     for (size_t field_i = 0; field_i < src_field_count; field_i += 1) {
                         ConstExprValue *field_val = &val->data.x_struct.fields[field_i];
                         field_val->special = ConstValSpecialStatic;
-                        TypeStructField *type_field = &val->type->data.structure.fields[field_i];
-                        field_val->type = type_field->type_entry;
-                        if (type_field->gen_index == SIZE_MAX)
+                        TypeStructField *struct_field = &val->type->data.structure.fields[field_i];
+                        field_val->type = struct_field->type_entry;
+                        if (struct_field->gen_index == SIZE_MAX)
                             continue;
-                        size_t offset = LLVMOffsetOfElement(codegen->target_data_ref, val->type->type_ref,
-                                type_field->gen_index);
+                        size_t offset = struct_field->offset;
                         uint8_t *new_buf = buf + offset;
                         if ((err = buf_read_value_bytes(ira, codegen, source_node, new_buf, field_val)))
                             return err;
@@ -21630,16 +21619,13 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
                     size_t child_buf_len = 16;
                     uint8_t *child_buf = child_buf_prealloc;
                     while (gen_i < gen_field_count) {
-                        LLVMTypeRef gen_llvm_int_type = LLVMStructGetTypeAtIndex(val->type->type_ref,
-                                    (unsigned)gen_i);
-                        size_t big_int_bit_count = LLVMGetIntTypeWidth(gen_llvm_int_type);
-                        size_t big_int_byte_count = big_int_bit_count / 8;
+                        size_t big_int_byte_count = val->type->data.structure.host_int_bytes[gen_i];
                         if (big_int_byte_count > child_buf_len) {
                             child_buf = allocate_nonzero<uint8_t>(big_int_byte_count);
                             child_buf_len = big_int_byte_count;
                         }
                         BigInt big_int;
-                        bigint_read_twos_complement(&big_int, buf + offset, big_int_bit_count, is_big_endian, false);
+                        bigint_read_twos_complement(&big_int, buf + offset, big_int_byte_count * 8, is_big_endian, false);
                         while (src_i < src_field_count) {
                             TypeStructField *field = &val->type->data.structure.fields[src_i];
                             assert(field->gen_index != SIZE_MAX);
@@ -21662,7 +21648,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
                                 big_int = tmp;
                             }
 
-                            bigint_write_twos_complement(&child_val, child_buf, big_int_bit_count, is_big_endian);
+                            bigint_write_twos_complement(&child_val, child_buf, big_int_byte_count * 8, is_big_endian);
                             if ((err = buf_read_value_bytes(ira, codegen, source_node, child_buf, field_val))) {
                                 return err;
                             }