Commit b28f7d0808

Andrew Kelley <superjoe30@gmail.com>
2016-02-03 08:42:24
types sized and aligned with LLVM target data layout API
1 parent b04e64d
src/all_types.hpp
@@ -807,6 +807,11 @@ struct TypeTableEntryPointer {
 
 struct TypeTableEntryInt {
     bool is_signed;
+    int bit_count;
+};
+
+struct TypeTableEntryFloat {
+    int bit_count;
 };
 
 struct TypeTableEntryArray {
@@ -910,17 +915,17 @@ enum TypeTableEntryId {
 
 struct TypeTableEntry {
     TypeTableEntryId id;
+    Buf name;
 
     LLVMTypeRef type_ref;
     LLVMZigDIType *di_type;
-    uint64_t size_in_bits;
-    uint64_t align_in_bits;
 
-    Buf name;
+    bool zero_bits;
 
     union {
         TypeTableEntryPointer pointer;
         TypeTableEntryInt integral;
+        TypeTableEntryFloat floating;
         TypeTableEntryArray array;
         TypeTableEntryStruct structure;
         TypeTableEntryMaybe maybe;
@@ -988,6 +993,7 @@ enum BuiltinFnId {
     BuiltinFnIdMemcpy,
     BuiltinFnIdMemset,
     BuiltinFnIdSizeof,
+    BuiltinFnIdAlignof,
     BuiltinFnIdMaxValue,
     BuiltinFnIdMinValue,
     BuiltinFnIdMemberCount,
src/analyze.cpp
@@ -200,27 +200,21 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
         TypeTableEntry *canon_child_type = get_underlying_type(child_type);
         assert(canon_child_type->id != TypeTableEntryIdInvalid);
 
-        bool zero_bits;
-        if (canon_child_type->size_in_bits == 0) {
-            if (canon_child_type->id == TypeTableEntryIdStruct) {
-                zero_bits = canon_child_type->data.structure.complete;
-            } else if (canon_child_type->id == TypeTableEntryIdEnum) {
-                zero_bits = canon_child_type->data.enumeration.complete;
-            } else {
-                zero_bits = true;
-            }
+
+        if (type_is_complete(canon_child_type)) {
+            entry->zero_bits = !type_has_bits(canon_child_type);
         } else {
-            zero_bits = false;
+            entry->zero_bits = false;
         }
 
-        if (!zero_bits) {
+        if (!entry->zero_bits) {
             entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
 
-            entry->size_in_bits = g->pointer_size_bytes * 8;
-            entry->align_in_bits = g->pointer_size_bytes * 8;
+            uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
             assert(child_type->di_type);
             entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
-                    entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
+                    debug_size_in_bits, debug_align_in_bits, buf_ptr(&entry->name));
         }
 
         entry->data.pointer.child_type = child_type;
@@ -249,8 +243,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_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->size_in_bits = child_type->size_in_bits;
-            entry->align_in_bits = child_type->align_in_bits;
             entry->type_ref = child_type->type_ref;
             entry->di_type = child_type->di_type;
         } else {
@@ -260,8 +252,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
                 LLVMInt1Type(),
             };
             entry->type_ref = LLVMStructType(elem_types, 2, false);
-            entry->size_in_bits = child_type->size_in_bits + 8;
-            entry->align_in_bits = child_type->align_in_bits;
 
 
             LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
@@ -271,18 +261,36 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
                 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
                 compile_unit_scope, di_file, line);
 
+            uint64_t val_debug_size_in_bits = LLVMSizeOfTypeInBits(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);
+
+            TypeTableEntry *bool_type = g->builtin_types.entry_bool;
+            uint64_t maybe_debug_size_in_bits = LLVMSizeOfTypeInBits(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 = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
+
             LLVMZigDIType *di_element_types[] = {
                 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                        "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
-                        child_type->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),
                 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                        "maybe", di_file, line, 8, 8, child_type->size_in_bits, 0,
-                        child_type->di_type),
+                        "maybe", di_file, line,
+                        maybe_debug_size_in_bits,
+                        maybe_debug_align_in_bits,
+                        maybe_offset_in_bits,
+                        0, child_type->di_type),
             };
             LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
                     compile_unit_scope,
                     buf_ptr(&entry->name),
-                    di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
+                    di_file, line, debug_size_in_bits, debug_align_in_bits, 0,
                     nullptr, di_element_types, 2, 0, nullptr, "");
 
             LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
@@ -309,10 +317,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
 
         entry->data.error.child_type = child_type;
 
-        if (child_type->size_in_bits == 0) {
+        if (!type_has_bits(child_type)) {
             entry->type_ref = g->err_tag_type->type_ref;
-            entry->size_in_bits = g->err_tag_type->size_in_bits;
-            entry->align_in_bits = g->err_tag_type->align_in_bits;
             entry->di_type = g->err_tag_type->di_type;
 
         } else {
@@ -321,8 +327,6 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
                 child_type->type_ref,
             };
             entry->type_ref = LLVMStructType(elem_types, 2, false);
-            entry->size_in_bits = g->err_tag_type->size_in_bits + child_type->size_in_bits;
-            entry->align_in_bits = g->err_tag_type->align_in_bits;
 
             LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
             LLVMZigDIFile *di_file = nullptr;
@@ -331,19 +335,39 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
                 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
                 compile_unit_scope, di_file, line);
 
+            uint64_t tag_debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, g->err_tag_type->type_ref);
+            uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
+            uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0);
+
+            uint64_t value_debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, child_type->type_ref);
+            uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref);
+            uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1);
+
+            uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
+
             LLVMZigDIType *di_element_types[] = {
                 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                        "tag", di_file, line, g->err_tag_type->size_in_bits, g->err_tag_type->align_in_bits,
-                        0, 0, child_type->di_type),
+                        "tag", di_file, line,
+                        tag_debug_size_in_bits,
+                        tag_debug_align_in_bits,
+                        tag_offset_in_bits,
+                        0, child_type->di_type),
                 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
-                        "value", di_file, line, child_type->size_in_bits, child_type->align_in_bits,
-                        g->err_tag_type->size_in_bits, 0, child_type->di_type),
+                        "value", di_file, line,
+                        value_debug_size_in_bits,
+                        value_debug_align_in_bits,
+                        value_offset_in_bits,
+                        0, child_type->di_type),
             };
 
             LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
                     compile_unit_scope,
                     buf_ptr(&entry->name),
-                    di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
+                    di_file, line,
+                    debug_size_in_bits,
+                    debug_align_in_bits,
+                    0,
                     nullptr, di_element_types, 2, 0, nullptr, "");
 
             LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
@@ -363,14 +387,16 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
     } else {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
         entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
+        entry->zero_bits = (array_size == 0) || child_type->zero_bits;
+
         buf_resize(&entry->name, 0);
         buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
 
-        entry->size_in_bits = child_type->size_in_bits * array_size;
-        entry->align_in_bits = child_type->align_in_bits;
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
 
-        entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, entry->size_in_bits,
-                entry->align_in_bits, child_type->di_type, array_size);
+        entry->di_type = LLVMZigCreateDebugArrayType(g->dbuilder, debug_size_in_bits,
+                debug_align_in_bits, child_type->di_type, array_size);
         entry->data.array.child_type = child_type;
         entry->data.array.len = array_size;
 
@@ -379,14 +405,12 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
     }
 }
 
-static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *child_type,
+static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
         bool is_const, TypeTableEntry *entry)
 {
     TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
 
     unsigned element_count = 2;
-    entry->size_in_bits = g->pointer_size_bytes * 2 * 8;
-    entry->align_in_bits = g->pointer_size_bytes * 8;
     entry->data.structure.is_packed = false;
     entry->data.structure.is_unknown_size_array = true;
     entry->data.structure.src_field_count = element_count;
@@ -402,20 +426,20 @@ static void unknown_size_array_type_common_init(CodeGen *g, TypeTableEntry *chil
     entry->data.structure.fields[1].gen_index = 1;
 }
 
-static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
+static TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
     assert(child_type->id != TypeTableEntryIdInvalid);
     TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)];
 
     if (*parent_pointer) {
         return *parent_pointer;
     } else if (is_const) {
-        TypeTableEntry *var_peer = get_unknown_size_array_type(g, child_type, false);
+        TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
 
         buf_resize(&entry->name, 0);
         buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
 
-        unknown_size_array_type_common_init(g, child_type, is_const, entry);
+        slice_type_common_init(g, child_type, is_const, entry);
 
         entry->type_ref = var_peer->type_ref;
         entry->di_type = var_peer->di_type;
@@ -439,15 +463,17 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c
         };
         LLVMStructSetBody(entry->type_ref, element_types, element_count, false);
 
-        unknown_size_array_type_common_init(g, child_type, is_const, entry);
+        slice_type_common_init(g, child_type, is_const, entry);
 
         LLVMZigDIType *di_element_types[] = {
             pointer_type->di_type,
             g->builtin_types.entry_isize->di_type,
         };
         LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugStructType(g->dbuilder, compile_unit_scope,
-                buf_ptr(&entry->name), g->dummy_di_file, 0, entry->size_in_bits, entry->align_in_bits, 0,
+                buf_ptr(&entry->name), g->dummy_di_file, 0, debug_size_in_bits, debug_align_in_bits, 0,
                 nullptr, di_element_types, element_count, 0, nullptr, "");
 
         entry->data.structure.complete = true;
@@ -462,11 +488,9 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
 
     buf_init_from_str(&entry->name, name);
 
-    entry->type_ref = child_type->type_ref;
     entry->type_ref = child_type->type_ref;
     entry->di_type = child_type->di_type;
-    entry->size_in_bits = child_type->size_in_bits;
-    entry->align_in_bits = child_type->align_in_bits;
+    entry->zero_bits = child_type->zero_bits;
 
     entry->data.type_decl.child_type = child_type;
 
@@ -497,9 +521,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
         fn_type->data.fn.calling_convention = LLVMFastCallConv;
     }
 
-    fn_type->size_in_bits = g->pointer_size_bytes * 8;
-    fn_type->align_in_bits = g->pointer_size_bytes * 8;
-
     // populate the name of the type
     buf_resize(&fn_type->name, 0);
     const char *extern_str = fn_type_id.is_extern ? "extern " : "";
@@ -542,7 +563,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
         // after the gen_param_index += 1 because 0 is the return type
         param_di_types[gen_param_index] = gen_type->di_type;
         gen_return_type = g->builtin_types.entry_void;
-    } else if (fn_type_id.return_type->size_in_bits == 0) {
+    } else if (!type_has_bits(fn_type_id.return_type)) {
         gen_return_type = g->builtin_types.entry_void;
     } else {
         gen_return_type = fn_type_id.return_type;
@@ -559,7 +580,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
         gen_param_info->gen_index = -1;
 
         assert(type_is_complete(type_entry));
-        if (type_entry->size_in_bits > 0) {
+        if (type_has_bits(type_entry)) {
             TypeTableEntry *gen_type;
             if (handle_is_ptr(type_entry)) {
                 gen_type = get_pointer_to_type(g, type_entry, true);
@@ -897,37 +918,43 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
         AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
         TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
         type_enum_field->name = &field_node->data.struct_field.name;
-        type_enum_field->type_entry = analyze_type_expr(g, import, import->block_context,
+        TypeTableEntry *field_type = analyze_type_expr(g, import, import->block_context,
                 field_node->data.struct_field.type);
+        type_enum_field->type_entry = field_type;
         type_enum_field->value = i;
 
+
         di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
 
-        if (type_enum_field->type_entry->id == TypeTableEntryIdStruct) {
-            resolve_struct_type(g, import, type_enum_field->type_entry);
-        } else if (type_enum_field->type_entry->id == TypeTableEntryIdEnum) {
-            resolve_enum_type(g, import, type_enum_field->type_entry);
-        } else if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) {
+        if (field_type->id == TypeTableEntryIdStruct) {
+            resolve_struct_type(g, import, field_type);
+        } else if (field_type->id == TypeTableEntryIdEnum) {
+            resolve_enum_type(g, import, field_type);
+        } else if (field_type->id == TypeTableEntryIdInvalid) {
             enum_type->data.enumeration.is_invalid = true;
             continue;
-        } else if (type_enum_field->type_entry->id == TypeTableEntryIdVoid) {
+        } else if (!type_has_bits(field_type)) {
             continue;
         }
 
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, field_type->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);
+
         union_inner_di_types[gen_field_index] = LLVMZigCreateDebugMemberType(g->dbuilder,
                 LLVMZigTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
                 import->di_file, field_node->line + 1,
-                type_enum_field->type_entry->size_in_bits,
-                type_enum_field->type_entry->align_in_bits,
-                0, 0, type_enum_field->type_entry->di_type);
+                debug_size_in_bits,
+                debug_align_in_bits,
+                0,
+                0, field_type->di_type);
 
-        biggest_align_in_bits = max(biggest_align_in_bits, type_enum_field->type_entry->align_in_bits);
+        biggest_align_in_bits = max(biggest_align_in_bits, debug_align_in_bits);
 
         if (!biggest_union_member ||
-            type_enum_field->type_entry->size_in_bits > biggest_union_member->size_in_bits)
+            debug_size_in_bits > biggest_union_member_size_in_bits)
         {
-            biggest_union_member = type_enum_field->type_entry;
-            biggest_union_member_size_in_bits = biggest_union_member->size_in_bits;
+            biggest_union_member = field_type;
+            biggest_union_member_size_in_bits = debug_size_in_bits;
         }
 
         gen_field_index += 1;
@@ -941,8 +968,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
         enum_type->data.enumeration.gen_field_count = gen_field_index;
 
         TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
-        enum_type->align_in_bits = tag_type_entry->size_in_bits;
-        enum_type->size_in_bits = tag_type_entry->size_in_bits + biggest_union_member_size_in_bits;
         enum_type->data.enumeration.tag_type = tag_type_entry;
 
         if (biggest_union_member) {
@@ -958,30 +983,37 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
             LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
 
             // create debug type for tag
+            uint64_t tag_debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, tag_type_entry->type_ref);
+            uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
             LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(g->dbuilder,
                     LLVMZigTypeToScope(enum_type->di_type), "AnonEnum", import->di_file, decl_node->line + 1,
-                    tag_type_entry->size_in_bits, tag_type_entry->align_in_bits, di_enumerators, field_count,
+                    tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
                     tag_type_entry->di_type, "");
 
             // create debug type for union
             LLVMZigDIType *union_di_type = LLVMZigCreateDebugUnionType(g->dbuilder,
                     LLVMZigTypeToScope(enum_type->di_type), "AnonUnion", import->di_file, decl_node->line + 1,
-                    biggest_union_member->size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
+                    biggest_union_member_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
                     gen_field_index, 0, "");
 
             // create debug types for members of root struct
+            uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 0);
             LLVMZigDIType *tag_member_di_type = LLVMZigCreateDebugMemberType(g->dbuilder,
                     LLVMZigTypeToScope(enum_type->di_type), "tag_field",
                     import->di_file, decl_node->line + 1,
-                    tag_type_entry->size_in_bits,
-                    tag_type_entry->align_in_bits,
-                    0, 0, tag_di_type);
+                    tag_debug_size_in_bits,
+                    tag_debug_align_in_bits,
+                    tag_offset_in_bits,
+                    0, tag_di_type);
+
+            uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 1);
             LLVMZigDIType *union_member_di_type = LLVMZigCreateDebugMemberType(g->dbuilder,
                     LLVMZigTypeToScope(enum_type->di_type), "union_field",
                     import->di_file, decl_node->line + 1,
-                    biggest_union_member->size_in_bits,
+                    biggest_union_member_size_in_bits,
                     biggest_align_in_bits,
-                    tag_type_entry->size_in_bits, 0, union_di_type);
+                    union_offset_in_bits,
+                    0, union_di_type);
 
             // create debug type for root struct
             LLVMZigDIType *di_root_members[] = {
@@ -990,11 +1022,15 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
             };
 
 
+            uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, enum_type->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
             LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
                     LLVMZigFileToScope(import->di_file),
                     buf_ptr(&decl_node->data.struct_decl.name),
-                    import->di_file, decl_node->line + 1, enum_type->size_in_bits, enum_type->align_in_bits, 0,
-                    nullptr, di_root_members, 2, 0, nullptr, "");
+                    import->di_file, decl_node->line + 1,
+                    debug_size_in_bits,
+                    debug_align_in_bits,
+                    0, nullptr, di_root_members, 2, 0, nullptr, "");
 
             LLVMZigReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
             enum_type->di_type = replacement_di_type;
@@ -1003,10 +1039,14 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
             enum_type->type_ref = tag_type_entry->type_ref;
 
             // create debug type for tag
+            uint64_t tag_debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, tag_type_entry->type_ref);
+            uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
             LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(g->dbuilder,
                     LLVMZigFileToScope(import->di_file), buf_ptr(&decl_node->data.struct_decl.name),
                     import->di_file, decl_node->line + 1,
-                    tag_type_entry->size_in_bits, tag_type_entry->align_in_bits, di_enumerators, field_count,
+                    tag_debug_size_in_bits,
+                    tag_debug_align_in_bits,
+                    di_enumerators, field_count,
                     tag_type_entry->di_type, "");
 
             LLVMZigReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
@@ -1025,6 +1065,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
     AstNode *decl_node = struct_type->data.structure.decl_node;
 
     if (struct_type->data.structure.embedded_in_current) {
+        struct_type->data.structure.is_invalid = true;
         if (!struct_type->data.structure.reported_infinite_err) {
             struct_type->data.structure.reported_infinite_err = true;
             add_node_error(g, decl_node,
@@ -1049,11 +1090,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
     // we possibly allocate too much here since gen_field_count can be lower than field_count.
     // the only problem is potential wasted space though.
     LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
-    LLVMZigDIType **di_element_types = allocate<LLVMZigDIType*>(field_count);
-
-    uint64_t total_size_in_bits = 0;
-    uint64_t first_field_align_in_bits = 0;
-    uint64_t offset_in_bits = 0;
 
     // this field should be set to true only during the recursive calls to resolve_struct_type
     struct_type->data.structure.embedded_in_current = true;
@@ -1063,41 +1099,28 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
         AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
         TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
         type_struct_field->name = &field_node->data.struct_field.name;
-        type_struct_field->type_entry = analyze_type_expr(g, import, import->block_context,
+        TypeTableEntry *field_type = analyze_type_expr(g, import, import->block_context,
                 field_node->data.struct_field.type);
+        type_struct_field->type_entry = field_type;
         type_struct_field->src_index = i;
         type_struct_field->gen_index = -1;
 
-        if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {
-            resolve_struct_type(g, import, type_struct_field->type_entry);
-        } else if (type_struct_field->type_entry->id == TypeTableEntryIdEnum) {
-            resolve_enum_type(g, import, type_struct_field->type_entry);
-        } else if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {
+        if (field_type->id == TypeTableEntryIdStruct) {
+            resolve_struct_type(g, import, field_type);
+        } else if (field_type->id == TypeTableEntryIdEnum) {
+            resolve_enum_type(g, import, field_type);
+        } else if (field_type->id == TypeTableEntryIdInvalid) {
             struct_type->data.structure.is_invalid = true;
             continue;
-        } else if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
+        } else if (!type_has_bits(field_type)) {
             continue;
         }
 
         type_struct_field->gen_index = gen_field_index;
 
-        di_element_types[gen_field_index] = LLVMZigCreateDebugMemberType(g->dbuilder,
-                LLVMZigTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
-                import->di_file, field_node->line + 1,
-                type_struct_field->type_entry->size_in_bits,
-                type_struct_field->type_entry->align_in_bits,
-                offset_in_bits, 0, type_struct_field->type_entry->di_type);
-
-        element_types[gen_field_index] = type_struct_field->type_entry->type_ref;
-        assert(di_element_types[gen_field_index]);
+        element_types[gen_field_index] = field_type->type_ref;
         assert(element_types[gen_field_index]);
 
-        total_size_in_bits += type_struct_field->type_entry->size_in_bits;
-        if (first_field_align_in_bits == 0) {
-            first_field_align_in_bits = type_struct_field->type_entry->align_in_bits;
-        }
-        offset_in_bits += type_struct_field->type_entry->size_in_bits;
-
         gen_field_index += 1;
     }
     struct_type->data.structure.embedded_in_current = false;
@@ -1105,22 +1128,55 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
     struct_type->data.structure.gen_field_count = gen_field_index;
     struct_type->data.structure.complete = true;
 
-    if (!struct_type->data.structure.is_invalid) {
+    if (struct_type->data.structure.is_invalid) {
+        return;
+    }
 
-        LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_index, false);
+    int gen_field_count = gen_field_index;
+    LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, false);
 
-        struct_type->align_in_bits = first_field_align_in_bits;
-        struct_type->size_in_bits = total_size_in_bits;
+    LLVMZigDIType **di_element_types = allocate<LLVMZigDIType*>(gen_field_count);
 
-        LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
-                LLVMZigFileToScope(import->di_file),
-                buf_ptr(&decl_node->data.struct_decl.name),
-                import->di_file, decl_node->line + 1, struct_type->size_in_bits, struct_type->align_in_bits, 0,
-                nullptr, di_element_types, gen_field_index, 0, nullptr, "");
+    for (int i = 0; i < field_count; i += 1) {
+        AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
+        TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+        gen_field_index = type_struct_field->gen_index;
+        if (gen_field_index == -1) {
+            continue;
+        }
+
+        TypeTableEntry *field_type = type_struct_field->type_entry;
+
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, field_type->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);
+        uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref,
+                gen_field_index);
+        di_element_types[gen_field_index] = LLVMZigCreateDebugMemberType(g->dbuilder,
+                LLVMZigTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
+                import->di_file, field_node->line + 1,
+                debug_size_in_bits,
+                debug_align_in_bits,
+                debug_offset_in_bits,
+                0, field_type->di_type);
 
-        LLVMZigReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
-        struct_type->di_type = replacement_di_type;
+        assert(di_element_types[gen_field_index]);
     }
+
+
+    uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, struct_type->type_ref);
+    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
+    LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
+            LLVMZigFileToScope(import->di_file),
+            buf_ptr(&decl_node->data.struct_decl.name),
+            import->di_file, decl_node->line + 1,
+            debug_size_in_bits,
+            debug_align_in_bits,
+            0, nullptr, di_element_types, gen_field_count, 0, nullptr, "");
+
+    LLVMZigReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
+    struct_type->di_type = replacement_di_type;
+
+    struct_type->zero_bits = (debug_size_in_bits == 0);
 }
 
 static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
@@ -1498,7 +1554,7 @@ static void add_global_const_expr(CodeGen *g, Expr *expr) {
     if (expr->const_val.ok &&
         type_has_codegen_value(expr->type_entry) &&
         !expr->has_global_const &&
-        expr->type_entry->size_in_bits > 0)
+        type_has_bits(expr->type_entry))
     {
         g->global_const_list.append(expr);
         expr->has_global_const = true;
@@ -1517,7 +1573,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTa
     } else if (other_type->id == TypeTableEntryIdInt &&
                const_val->data.x_bignum.kind == BigNumKindInt)
     {
-        if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits,
+        if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->data.integral.bit_count,
                     other_type->data.integral.is_signed))
         {
             return true;
@@ -1653,14 +1709,14 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa
                    cur_type->id == TypeTableEntryIdInt &&
                    prev_type->data.integral.is_signed == cur_type->data.integral.is_signed)
         {
-            if (cur_type->size_in_bits > prev_type->size_in_bits) {
+            if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) {
                 prev_type = cur_type;
                 prev_node = cur_node;
             }
         } else if (prev_type->id == TypeTableEntryIdFloat &&
                    cur_type->id == TypeTableEntryIdFloat)
         {
-            if (cur_type->size_in_bits > prev_type->size_in_bits) {
+            if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) {
                 prev_type = cur_type;
                 prev_node = cur_node;
             }
@@ -1737,7 +1793,7 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
     if (expected_type->id == TypeTableEntryIdInt &&
         actual_type->id == TypeTableEntryIdInt &&
         expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
-        expected_type->size_in_bits >= actual_type->size_in_bits)
+        expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
     {
         return true;
     }
@@ -1745,7 +1801,7 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
     // implicit float widening conversion
     if (expected_type->id == TypeTableEntryIdFloat &&
         actual_type->id == TypeTableEntryIdFloat &&
-        expected_type->size_in_bits >= actual_type->size_in_bits)
+        expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
     {
         return true;
     }
@@ -2221,15 +2277,15 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
     if (array_type->id == TypeTableEntryIdInvalid) {
         return_type = g->builtin_types.entry_invalid;
     } else if (array_type->id == TypeTableEntryIdArray) {
-        return_type = get_unknown_size_array_type(g, array_type->data.array.child_type,
+        return_type = get_slice_type(g, array_type->data.array.child_type,
                 node->data.slice_expr.is_const);
     } else if (array_type->id == TypeTableEntryIdPointer) {
-        return_type = get_unknown_size_array_type(g, array_type->data.pointer.child_type,
+        return_type = get_slice_type(g, array_type->data.pointer.child_type,
                 node->data.slice_expr.is_const);
     } else if (array_type->id == TypeTableEntryIdStruct &&
                array_type->data.structure.is_unknown_size_array)
     {
-        return_type = get_unknown_size_array_type(g,
+        return_type = get_slice_type(g,
                 array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
                 node->data.slice_expr.is_const);
     } else {
@@ -2666,7 +2722,7 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
         bool are_equal = false;
         if (enum1->tag == enum2->tag) {
             TypeEnumField *enum_field = &op1_type->data.enumeration.fields[enum1->tag];
-            if (enum_field->type_entry->size_in_bits > 0) {
+            if (type_has_bits(enum_field->type_entry)) {
                 zig_panic("TODO const expr analyze enum special value for equality");
             } else {
                 are_equal = true;
@@ -2839,7 +2895,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
                 AstNode **op1 = node->data.bin_op_expr.op1->parent_field;
                 AstNode **op2 = node->data.bin_op_expr.op2->parent_field;
 
-                TypeTableEntry *str_type = get_unknown_size_array_type(g, g->builtin_types.entry_u8, true);
+                TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
 
                 TypeTableEntry *op1_type = analyze_expression(g, import, context, str_type, *op1);
                 TypeTableEntry *op2_type = analyze_expression(g, import, context, str_type, *op2);
@@ -3162,11 +3218,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
             }
         } else {
             return resolve_expr_const_val_as_type(g, node,
-                    get_unknown_size_array_type(g, child_type, node->data.array_type.is_const));
+                    get_slice_type(g, child_type, node->data.array_type.is_const));
         }
     } else {
         return resolve_expr_const_val_as_type(g, node,
-                get_unknown_size_array_type(g, child_type, node->data.array_type.is_const));
+                get_slice_type(g, child_type, node->data.array_type.is_const));
     }
 }
 
@@ -3357,13 +3413,13 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
         if (is_max) {
             if (type_entry->data.integral.is_signed) {
                 int64_t val;
-                if (type_entry->size_in_bits == 64) {
+                if (type_entry->data.integral.bit_count == 64) {
                     val = INT64_MAX;
-                } else if (type_entry->size_in_bits == 32) {
+                } else if (type_entry->data.integral.bit_count == 32) {
                     val = INT32_MAX;
-                } else if (type_entry->size_in_bits == 16) {
+                } else if (type_entry->data.integral.bit_count == 16) {
                     val = INT16_MAX;
-                } else if (type_entry->size_in_bits == 8) {
+                } else if (type_entry->data.integral.bit_count == 8) {
                     val = INT8_MAX;
                 } else {
                     zig_unreachable();
@@ -3371,13 +3427,13 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
                 bignum_init_signed(&const_val->data.x_bignum, val);
             } else {
                 uint64_t val;
-                if (type_entry->size_in_bits == 64) {
+                if (type_entry->data.integral.bit_count == 64) {
                     val = UINT64_MAX;
-                } else if (type_entry->size_in_bits == 32) {
+                } else if (type_entry->data.integral.bit_count == 32) {
                     val = UINT32_MAX;
-                } else if (type_entry->size_in_bits == 16) {
+                } else if (type_entry->data.integral.bit_count == 16) {
                     val = UINT16_MAX;
-                } else if (type_entry->size_in_bits == 8) {
+                } else if (type_entry->data.integral.bit_count == 8) {
                     val = UINT8_MAX;
                 } else {
                     zig_unreachable();
@@ -3387,13 +3443,13 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
         } else {
             if (type_entry->data.integral.is_signed) {
                 int64_t val;
-                if (type_entry->size_in_bits == 64) {
+                if (type_entry->data.integral.bit_count == 64) {
                     val = INT64_MIN;
-                } else if (type_entry->size_in_bits == 32) {
+                } else if (type_entry->data.integral.bit_count == 32) {
                     val = INT32_MIN;
-                } else if (type_entry->size_in_bits == 16) {
+                } else if (type_entry->data.integral.bit_count == 16) {
                     val = INT16_MIN;
-                } else if (type_entry->size_in_bits == 8) {
+                } else if (type_entry->data.integral.bit_count == 8) {
                     val = INT8_MIN;
                 } else {
                     zig_unreachable();
@@ -3657,14 +3713,16 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
 
     // explicit cast from %void to integer type which can fit it
     bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
-        actual_type->data.error.child_type->size_in_bits == 0;
+        !type_has_bits(actual_type->data.error.child_type);
     bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
     if ((actual_type_is_void_err || actual_type_is_pure_err) &&
         wanted_type->id == TypeTableEntryIdInt)
     {
         BigNum bn;
         bignum_init_unsigned(&bn, g->error_value_count);
-        if (bignum_fits_in_bits(&bn, wanted_type->size_in_bits, wanted_type->data.integral.is_signed)) {
+        if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
+                    wanted_type->data.integral.is_signed))
+        {
             node->data.fn_call_expr.cast_op = CastOpErrToInt;
             eval_const_expr_implicit_cast(g, node, expr_node);
             return wanted_type;
@@ -3767,13 +3825,13 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                 if (dest_type->id == TypeTableEntryIdPointer &&
                     src_type->id == TypeTableEntryIdPointer)
                 {
-                    uint64_t dest_align_bits = dest_type->data.pointer.child_type->align_in_bits;
-                    uint64_t src_align_bits = src_type->data.pointer.child_type->align_in_bits;
-                    if (dest_align_bits != src_align_bits) {
+                    uint64_t dest_align = get_memcpy_align(g, dest_type->data.pointer.child_type);
+                    uint64_t src_align = get_memcpy_align(g, src_type->data.pointer.child_type);
+                    if (dest_align != src_align) {
                         add_node_error(g, dest_node, buf_sprintf(
                             "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64,
-                                    buf_ptr(&dest_type->name), dest_align_bits / 8,
-                                    buf_ptr(&src_type->name), src_align_bits / 8));
+                                    buf_ptr(&dest_type->name), dest_align,
+                                    buf_ptr(&src_type->name), src_align));
                     }
                 }
 
@@ -3808,10 +3866,30 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                             buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
                     return g->builtin_types.entry_invalid;
                 } else {
-                    uint64_t size_in_bytes = type_entry->size_in_bits / 8;
+                    uint64_t size_in_bytes;
+                    if (type_has_bits(type_entry)) {
+                        size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
+                    } else {
+                        size_in_bytes = 0;
+                    }
                     return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, size_in_bytes);
                 }
             }
+        case BuiltinFnIdAlignof:
+            {
+                AstNode *type_node = node->data.fn_call_expr.params.at(0);
+                TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+                if (type_entry->id == TypeTableEntryIdInvalid) {
+                    return g->builtin_types.entry_invalid;
+                } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+                    add_node_error(g, first_executing_node(type_node),
+                            buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name)));
+                    return g->builtin_types.entry_invalid;
+                } else {
+                    uint64_t align_in_bytes = LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
+                    return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, align_in_bytes);
+                }
+            }
         case BuiltinFnIdMaxValue:
             return analyze_min_max_value(g, import, context, node,
                     "no max value available for type '%s'", true);
@@ -3874,7 +3952,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                 }
 
                 AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
-                TypeTableEntry *str_type = get_unknown_size_array_type(g, g->builtin_types.entry_u8, true);
+                TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
                 TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);
 
                 if (resolved_type->id == TypeTableEntryIdInvalid) {
@@ -3911,7 +3989,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
             {
                 AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
 
-                TypeTableEntry *str_type = get_unknown_size_array_type(g, g->builtin_types.entry_u8, true);
+                TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
                 TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);
 
                 if (resolved_type->id == TypeTableEntryIdInvalid) {
@@ -5317,8 +5395,6 @@ void semantic_analyze(CodeGen *g) {
         g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count);
 
         g->builtin_types.entry_pure_error->type_ref = g->err_tag_type->type_ref;
-        g->builtin_types.entry_pure_error->size_in_bits = g->err_tag_type->size_in_bits;
-        g->builtin_types.entry_pure_error->align_in_bits = g->err_tag_type->align_in_bits;
         g->builtin_types.entry_pure_error->di_type = g->err_tag_type->di_type;
     }
 
@@ -5571,7 +5647,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
         case TypeTableEntryIdStruct:
              return true;
         case TypeTableEntryIdErrorUnion:
-             return type_entry->data.error.child_type->size_in_bits > 0;
+             return type_has_bits(type_entry->data.error.child_type);
         case TypeTableEntryIdEnum:
              return type_entry->data.enumeration.gen_field_count != 0;
         case TypeTableEntryIdMaybe:
@@ -5640,3 +5716,59 @@ bool fn_type_id_eql(FnTypeId a, FnTypeId b) {
     }
     return true;
 }
+
+bool type_has_bits(TypeTableEntry *type_entry) {
+    assert(type_entry);
+    assert(type_entry->id != TypeTableEntryIdInvalid);
+    return !type_entry->zero_bits;
+}
+
+static TypeTableEntry *first_struct_field_type(TypeTableEntry *type_entry) {
+    assert(type_entry->id == TypeTableEntryIdStruct);
+    for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
+        TypeStructField *tsf = &type_entry->data.structure.fields[i];
+        if (tsf->gen_index == 0) {
+            return tsf->type_entry;
+        }
+    }
+    zig_unreachable();
+}
+
+static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) {
+    assert(type_has_bits(type_entry));
+    switch (type_entry->id) {
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdNumLitFloat:
+        case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdUndefLit:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdMetaType:
+        case TypeTableEntryIdVoid:
+            zig_unreachable();
+        case TypeTableEntryIdArray:
+            return type_of_first_thing_in_memory(type_entry->data.array.child_type);
+        case TypeTableEntryIdStruct:
+            return type_of_first_thing_in_memory(first_struct_field_type(type_entry));
+        case TypeTableEntryIdMaybe:
+            return type_of_first_thing_in_memory(type_entry->data.maybe.child_type);
+        case TypeTableEntryIdErrorUnion:
+            return type_of_first_thing_in_memory(type_entry->data.error.child_type);
+        case TypeTableEntryIdTypeDecl:
+            return type_of_first_thing_in_memory(type_entry->data.type_decl.canonical_type);
+        case TypeTableEntryIdEnum:
+            return type_entry->data.enumeration.tag_type;
+        case TypeTableEntryIdPureError:
+        case TypeTableEntryIdFn:
+        case TypeTableEntryIdBool:
+        case TypeTableEntryIdInt:
+        case TypeTableEntryIdFloat:
+        case TypeTableEntryIdPointer:
+            return type_entry;
+    }
+}
+
+uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) {
+    TypeTableEntry *first_type_in_mem = type_of_first_thing_in_memory(type_entry);
+    return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref);
+}
+
src/analyze.hpp
@@ -35,5 +35,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry);
 void find_libc_path(CodeGen *g);
 
 TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry);
+bool type_has_bits(TypeTableEntry *type_entry);
+uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry);
 
 #endif
src/codegen.cpp
@@ -145,8 +145,9 @@ static int bits_index(int size_in_bits) {
 static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
         const char *signed_name, const char *unsigned_name)
 {
+    assert(type_entry->id == TypeTableEntryIdInt);
     const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;
-    Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
+    Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%d", signed_str, type_entry->data.integral.bit_count);
 
     LLVMTypeRef return_elem_types[] = {
         type_entry->type_ref,
@@ -168,7 +169,7 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
     // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
     int index0 = type_entry->data.integral.is_signed ? 0 : 1;
     int index1 = add_sub_mul;
-    int index2 = bits_index(type_entry->size_in_bits);
+    int index2 = bits_index(type_entry->data.integral.bit_count);
     LLVMValueRef *fn = &g->int_overflow_fns[index0][index1][index2];
     if (*fn) {
         return *fn;
@@ -188,7 +189,6 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry,
     return *fn;
 }
 
-
 static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
     assert(node->type == NodeTypeFnCallExpr);
     AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -257,7 +257,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
                 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
                 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, "");
 
-                uint64_t align_in_bytes = dest_type->data.pointer.child_type->align_in_bits / 8;
+                uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
 
                 LLVMValueRef params[] = {
                     dest_ptr_casted, // dest pointer
@@ -287,7 +287,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
                 add_debug_source_node(g, node);
                 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, "");
 
-                uint64_t align_in_bytes = dest_type->data.pointer.child_type->align_in_bits / 8;
+                uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type);
 
                 LLVMValueRef params[] = {
                     dest_ptr_casted, // dest pointer
@@ -301,6 +301,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
                 return nullptr;
             }
         case BuiltinFnIdSizeof:
+        case BuiltinFnIdAlignof:
         case BuiltinFnIdMinValue:
         case BuiltinFnIdMaxValue:
         case BuiltinFnIdMemberCount:
@@ -359,9 +360,21 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
         TypeTableEntry *wanted_type, LLVMValueRef expr_val)
 {
     assert(actual_type->id == wanted_type->id);
-    if (actual_type->size_in_bits == wanted_type->size_in_bits) {
+    uint64_t actual_bits;
+    uint64_t wanted_bits;
+    if (actual_type->id == TypeTableEntryIdFloat) {
+        actual_bits = actual_type->data.floating.bit_count;
+        wanted_bits = wanted_type->data.floating.bit_count;
+    } else if (actual_type->id == TypeTableEntryIdInt) {
+        actual_bits = actual_type->data.integral.bit_count;
+        wanted_bits = wanted_type->data.integral.bit_count;
+    } else {
+        zig_unreachable();
+    }
+
+    if (actual_bits == wanted_bits) {
         return expr_val;
-    } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
+    } else if (actual_bits < wanted_bits) {
         if (actual_type->id == TypeTableEntryIdFloat) {
             add_debug_source_node(g, source_node);
             return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
@@ -376,7 +389,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
         } else {
             zig_unreachable();
         }
-    } else if (actual_type->size_in_bits > wanted_type->size_in_bits) {
+    } else if (actual_bits > wanted_bits) {
         if (actual_type->id == TypeTableEntryIdFloat) {
             add_debug_source_node(g, source_node);
             return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
@@ -410,7 +423,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
             return expr_val;
         case CastOpErrToInt:
             assert(actual_type->id == TypeTableEntryIdErrorUnion);
-            if (actual_type->data.error.child_type->size_in_bits == 0) {
+            if (!type_has_bits(actual_type->data.error.child_type)) {
                 return gen_widen_or_shorten(g, node, g->err_tag_type, wanted_type, expr_val);
             } else {
                 zig_panic("TODO");
@@ -446,7 +459,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
                 TypeTableEntry *child_type = wanted_type->data.error.child_type;
                 LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
 
-                if (child_type->size_in_bits == 0) {
+                if (!type_has_bits(child_type)) {
                     return ok_err_val;
                 } else {
                     assert(cast_expr->tmp_ptr);
@@ -466,7 +479,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
             }
         case CastOpPureErrorWrap:
             assert(wanted_type->id == TypeTableEntryIdErrorUnion);
-            if (wanted_type->data.error.child_type->size_in_bits == 0) {
+            if (!type_has_bits(wanted_type->data.error.child_type)) {
                 return expr_val;
             } else {
                 zig_panic("TODO");
@@ -607,7 +620,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
         AstNode *expr_node = node->data.fn_call_expr.params.at(i);
         LLVMValueRef param_value = gen_expr(g, expr_node);
         TypeTableEntry *param_type = get_expr_type(expr_node);
-        if (is_var_args || param_type->size_in_bits > 0) {
+        if (is_var_args || type_has_bits(param_type)) {
             gen_param_values[gen_param_index] = param_value;
             gen_param_index += 1;
         }
@@ -621,7 +634,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
         return LLVMBuildUnreachable(g->builder);
     } else if (first_arg_ret) {
         return node->data.fn_call_expr.tmp_ptr;
-    } else if (src_return_type->size_in_bits == 0) {
+    } else if (!type_has_bits(src_return_type)) {
         return nullptr;
     } else {
         return result;
@@ -653,7 +666,7 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal
 {
     assert(subscript_value);
 
-    if (array_type->size_in_bits == 0) {
+    if (!type_has_bits(array_type)) {
         return nullptr;
     }
 
@@ -978,7 +991,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
         case PrefixOpDereference:
             {
                 LLVMValueRef expr = gen_expr(g, expr_node);
-                if (expr_type->size_in_bits == 0) {
+                if (!type_has_bits(expr_type)) {
                     return nullptr;
                 } else {
                     add_debug_source_node(g, node);
@@ -1002,7 +1015,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
 
                 if (g->build_type != CodeGenBuildTypeRelease) {
                     LLVMValueRef err_val;
-                    if (child_type->size_in_bits > 0) {
+                    if (type_has_bits(child_type)) {
                         add_debug_source_node(g, node);
                         LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
                         err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
@@ -1022,7 +1035,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
                     LLVMPositionBuilderAtEnd(g->builder, ok_block);
                 }
 
-                if (child_type->size_in_bits > 0) {
+                if (type_has_bits(child_type)) {
                     LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
                     if (handle_is_ptr(child_type)) {
                         return child_val_ptr;
@@ -1337,11 +1350,15 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValu
     LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, src, ptr_u8, "");
     LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, dest, ptr_u8, "");
 
+    TypeTableEntry *isize = g->builtin_types.entry_isize;
+    uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
+    uint64_t align_bytes = get_memcpy_align(g, type_entry);
+
     LLVMValueRef params[] = {
         dest_ptr, // dest pointer
         src_ptr, // source pointer
-        LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8), type_entry->size_in_bits / 8, false), // byte count
-        LLVMConstInt(LLVMInt32Type(), type_entry->align_in_bits / 8, false), // align in bytes
+        LLVMConstInt(isize->type_ref, size_bytes, false),
+        LLVMConstInt(LLVMInt32Type(), align_bytes, false),
         LLVMConstNull(LLVMInt1Type()), // is volatile
     };
 
@@ -1384,7 +1401,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
 
     LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
 
-    if (op1_type->size_in_bits == 0) {
+    if (!type_has_bits(op1_type)) {
         return nullptr;
     }
 
@@ -1546,7 +1563,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
     LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
     LLVMBasicBlockRef end_block;
     bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable;
-    bool have_end_block = err_reachable && (child_type->size_in_bits > 0);
+    bool have_end_block = err_reachable && type_has_bits(child_type);
     if (have_end_block) {
         end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd");
     }
@@ -1566,7 +1583,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
     }
 
     LLVMPositionBuilderAtEnd(g->builder, ok_block);
-    if (child_type->size_in_bits == 0) {
+    if (!type_has_bits(child_type)) {
         return nullptr;
     }
     LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
@@ -1624,7 +1641,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
 
                 add_debug_source_node(g, node);
                 LLVMValueRef err_val;
-                if (child_type->size_in_bits > 0) {
+                if (type_has_bits(child_type)) {
                     LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
                     err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
                 } else {
@@ -1639,7 +1656,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
                 if (return_type->id == TypeTableEntryIdPureError) {
                     gen_return(g, node, err_val);
                 } else if (return_type->id == TypeTableEntryIdErrorUnion) {
-                    if (return_type->data.error.child_type->size_in_bits > 0) {
+                    if (type_has_bits(return_type->data.error.child_type)) {
                         assert(g->cur_ret_ptr);
 
                         add_debug_source_node(g, node);
@@ -1654,7 +1671,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
                 }
 
                 LLVMPositionBuilderAtEnd(g->builder, continue_block);
-                if (child_type->size_in_bits > 0) {
+                if (type_has_bits(child_type)) {
                     add_debug_source_node(g, node);
                     LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
                     if (handle_is_ptr(child_type)) {
@@ -2164,7 +2181,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
         *init_value = gen_expr(g, var_decl->expr);
         *expr_type = get_expr_type(var_decl->expr);
     }
-    if (variable->type->size_in_bits == 0) {
+    if (!type_has_bits(variable->type)) {
         return nullptr;
     }
 
@@ -2225,15 +2242,17 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
             }
         }
         if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
+            TypeTableEntry *isize = g->builtin_types.entry_isize;
+            uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref);
+            uint64_t align_bytes = get_memcpy_align(g, variable->type);
+
             // memset uninitialized memory to 0xa
             add_debug_source_node(g, source_node);
             LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
             LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
             LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
-            LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
-                    variable->type->size_in_bits / 8, false);
-            LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
-                    variable->type->align_in_bits / 8, false);
+            LLVMValueRef byte_count = LLVMConstInt(isize->type_ref, size_bytes, false);
+            LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
             LLVMValueRef params[] = {
                 dest_ptr,
                 fill_char,
@@ -2273,7 +2292,7 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
     assert(node->type == NodeTypeSymbol);
     VariableTableEntry *variable = node->data.symbol_expr.variable;
     if (variable) {
-        if (variable->type->size_in_bits == 0) {
+        if (!type_has_bits(variable->type)) {
             return nullptr;
         } else if (variable->is_ptr) {
             assert(variable->value_ref);
@@ -2364,7 +2383,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
 static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
     Expr *expr = get_resolved_expr(node);
     if (expr->const_val.ok) {
-        if (expr->type_entry->size_in_bits == 0) {
+        if (!type_has_bits(expr->type_entry)) {
             return nullptr;
         } else {
             assert(expr->const_llvm_val);
@@ -2600,7 +2619,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
         case TypeTableEntryIdErrorUnion:
             {
                 TypeTableEntry *child_type = type_entry->data.error.child_type;
-                if (child_type->size_in_bits == 0) {
+                if (!type_has_bits(child_type)) {
                     uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
                     return LLVMConstInt(g->err_tag_type->type_ref, value, false);
                 } else {
@@ -2683,7 +2702,7 @@ static void do_code_gen(CodeGen *g) {
 
         if (var->type->id == TypeTableEntryIdNumLitFloat ||
             var->type->id == TypeTableEntryIdNumLitInt ||
-            var->type->size_in_bits == 0)
+            !type_has_bits(var->type))
         {
             continue;
         }
@@ -2820,7 +2839,7 @@ static void do_code_gen(CodeGen *g) {
             for (int var_i = 0; var_i < block_context->variable_list.length; var_i += 1) {
                 VariableTableEntry *var = block_context->variable_list.at(var_i);
 
-                if (var->type->size_in_bits == 0) {
+                if (!type_has_bits(var->type)) {
                     continue;
                 }
 
@@ -2839,7 +2858,8 @@ static void do_code_gen(CodeGen *g) {
 
                     add_debug_source_node(g, var->decl_node);
                     var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
-                    LLVMSetAlignment(var->value_ref, var->type->align_in_bits / 8);
+                    uint64_t align_bytes = LLVMABISizeOfType(g->target_data_ref, var->type->type_ref);
+                    LLVMSetAlignment(var->value_ref, align_bytes);
                 }
 
                 var->di_loc_var = LLVMZigCreateLocalVariable(g->dbuilder, tag,
@@ -2953,16 +2973,19 @@ static void define_builtin_types(CodeGen *g) {
         // if this type is anywhere in the AST, we should never hit codegen.
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInvalid);
         buf_init_from_str(&entry->name, "(invalid)");
+        entry->zero_bits = true;
         g->builtin_types.entry_invalid = entry;
     }
     {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
         buf_init_from_str(&entry->name, "(float literal)");
+        entry->zero_bits = true;
         g->builtin_types.entry_num_lit_float = entry;
     }
     {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
         buf_init_from_str(&entry->name, "(integer literal)");
+        entry->zero_bits = true;
         g->builtin_types.entry_num_lit_int = entry;
     }
     {
@@ -2982,12 +3005,13 @@ static void define_builtin_types(CodeGen *g) {
             buf_resize(&entry->name, 0);
             buf_appendf(&entry->name, "%c%d", u_or_i, size_in_bits);
 
-            entry->size_in_bits = size_in_bits;
-            entry->align_in_bits = size_in_bits;
+            uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+            uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
             entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                    entry->size_in_bits, entry->align_in_bits,
+                    debug_size_in_bits, debug_align_in_bits,
                     is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_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);
 
             get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
@@ -3010,13 +3034,14 @@ static void define_builtin_types(CodeGen *g) {
 
         buf_init_from_str(&entry->name, info->name);
 
-        entry->size_in_bits = size_in_bits;
-        entry->align_in_bits = size_in_bits;
-
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_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);
 
         get_c_int_type_ptr(g, info->id)[0] = entry;
@@ -3026,10 +3051,11 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
         entry->type_ref = LLVMInt1Type();
         buf_init_from_str(&entry->name, "bool");
-        entry->size_in_bits = 8;
-        entry->align_in_bits = 8;
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_unsigned());
         g->builtin_types.entry_bool = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3038,12 +3064,14 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
         entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
         buf_init_from_str(&entry->name, "isize");
-        entry->size_in_bits = g->pointer_size_bytes * 8;
-        entry->align_in_bits = g->pointer_size_bytes * 8;
         entry->data.integral.is_signed = true;
+        entry->data.integral.bit_count = g->pointer_size_bytes * 8;
 
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_signed());
         g->builtin_types.entry_isize = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3052,12 +3080,14 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
         entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
         buf_init_from_str(&entry->name, "usize");
-        entry->size_in_bits = g->pointer_size_bytes * 8;
-        entry->align_in_bits = g->pointer_size_bytes * 8;
         entry->data.integral.is_signed = false;
+        entry->data.integral.bit_count = g->pointer_size_bytes * 8;
 
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_unsigned());
         g->builtin_types.entry_usize = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3066,10 +3096,13 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
         entry->type_ref = LLVMFloatType();
         buf_init_from_str(&entry->name, "f32");
-        entry->size_in_bits = 32;
-        entry->align_in_bits = 32;
+        entry->data.floating.bit_count = 32;
+
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_float());
         g->builtin_types.entry_f32 = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3078,10 +3111,13 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
         entry->type_ref = LLVMDoubleType();
         buf_init_from_str(&entry->name, "f64");
-        entry->size_in_bits = 64;
-        entry->align_in_bits = 64;
+        entry->data.floating.bit_count = 64;
+
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_float());
         g->builtin_types.entry_f64 = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3090,10 +3126,13 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
         entry->type_ref = LLVMX86FP80Type();
         buf_init_from_str(&entry->name, "c_long_double");
-        entry->size_in_bits = 128;
-        entry->align_in_bits = 128;
+        entry->data.floating.bit_count = 80;
+
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(g->target_data_ref, entry->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                80, entry->align_in_bits,
+                debug_size_in_bits,
+                debug_align_in_bits,
                 LLVMZigEncoding_DW_ATE_float());
         g->builtin_types.entry_c_long_double = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3101,9 +3140,11 @@ static void define_builtin_types(CodeGen *g) {
     {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
         entry->type_ref = LLVMVoidType();
+        entry->zero_bits = true;
         buf_init_from_str(&entry->name, "void");
         entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                entry->size_in_bits, entry->align_in_bits,
+                0,
+                0,
                 LLVMZigEncoding_DW_ATE_unsigned());
         g->builtin_types.entry_void = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -3111,6 +3152,7 @@ static void define_builtin_types(CodeGen *g) {
     {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
         entry->type_ref = LLVMVoidType();
+        entry->zero_bits = true;
         buf_init_from_str(&entry->name, "unreachable");
         entry->di_type = g->builtin_types.entry_void->di_type;
         g->builtin_types.entry_unreachable = entry;
@@ -3119,6 +3161,7 @@ static void define_builtin_types(CodeGen *g) {
     {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
         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);
     }
@@ -3212,6 +3255,7 @@ static void define_builtin_fns(CodeGen *g) {
         g->memset_fn_val = builtin_fn->fn_val;
     }
     create_builtin_fn_with_arg_count(g, BuiltinFnIdSizeof, "sizeof", 1);
+    create_builtin_fn_with_arg_count(g, BuiltinFnIdAlignof, "alignof", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdMaxValue, "max_value", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdMinValue, "min_value", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdMemberCount, "member_count", 1);
src/parseh.cpp
@@ -740,8 +740,6 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
     enum_type->data.enumeration.complete = true;
 
     TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(c->codegen, field_count);
-    enum_type->align_in_bits = tag_type_entry->size_in_bits;
-    enum_type->size_in_bits = tag_type_entry->size_in_bits;
     enum_type->data.enumeration.tag_type = tag_type_entry;
 
     c->enum_type_table.put(bare_name, enum_type);
@@ -795,11 +793,14 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
 
     // create debug type for tag
     unsigned line = c->source_node ? (c->source_node->line + 1) : 0;
+    uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(c->codegen->target_data_ref, enum_type->type_ref);
+    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, enum_type->type_ref);
     LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(c->codegen->dbuilder,
             LLVMZigFileToScope(c->import->di_file), buf_ptr(bare_name),
             c->import->di_file, line,
-            tag_type_entry->size_in_bits, tag_type_entry->align_in_bits, di_enumerators, field_count,
-            tag_type_entry->di_type, "");
+            debug_size_in_bits,
+            debug_align_in_bits,
+            di_enumerators, field_count, tag_type_entry->di_type, "");
 
     LLVMZigReplaceTemporary(c->codegen->dbuilder, enum_type->di_type, tag_di_type);
     enum_type->di_type = tag_di_type;
@@ -894,10 +895,6 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
     LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
     LLVMZigDIType **di_element_types = allocate<LLVMZigDIType*>(field_count);
 
-    uint64_t total_size_in_bits = 0;
-    uint64_t first_field_align_in_bits = 0;
-    uint64_t offset_in_bits = 0;
-
     uint32_t i = 0;
     for (auto it = record_def->field_begin(),
               it_end = record_def->field_end();
@@ -909,30 +906,29 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
         type_struct_field->name = buf_create_from_str(decl_name(field_decl));
         type_struct_field->src_index = i;
         type_struct_field->gen_index = i;
-        type_struct_field->type_entry = resolve_qual_type(c, field_decl->getType(), field_decl);
+        TypeTableEntry *field_type = resolve_qual_type(c, field_decl->getType(), field_decl);
+        type_struct_field->type_entry = field_type;
 
-        if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {
+        if (field_type->id == TypeTableEntryIdInvalid) {
             emit_warning(c, field_decl, "struct %s demoted to typedef - unresolved type\n", buf_ptr(bare_name));
             return struct_type;
         }
 
+        uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(c->codegen->target_data_ref, field_type->type_ref);
+        uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, field_type->type_ref);
+        uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(c->codegen->target_data_ref, struct_type->type_ref, i);
         di_element_types[i] = LLVMZigCreateDebugMemberType(c->codegen->dbuilder,
                 LLVMZigTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
                 c->import->di_file, line + 1,
-                type_struct_field->type_entry->size_in_bits,
-                type_struct_field->type_entry->align_in_bits,
-                offset_in_bits, 0, type_struct_field->type_entry->di_type);
+                debug_size_in_bits,
+                debug_align_in_bits,
+                debug_offset_in_bits,
+                0, field_type->di_type);
 
-        element_types[i] = type_struct_field->type_entry->type_ref;
+        element_types[i] = field_type->type_ref;
         assert(di_element_types[i]);
         assert(element_types[i]);
 
-        total_size_in_bits += type_struct_field->type_entry->size_in_bits;
-        if (first_field_align_in_bits == 0) {
-            first_field_align_in_bits = type_struct_field->type_entry->align_in_bits;
-        }
-        offset_in_bits += type_struct_field->type_entry->size_in_bits;
-
     }
     struct_type->data.structure.embedded_in_current = false;
 
@@ -941,13 +937,14 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_
 
     LLVMStructSetBody(struct_type->type_ref, element_types, field_count, false);
 
-    struct_type->align_in_bits = first_field_align_in_bits;
-    struct_type->size_in_bits = total_size_in_bits;
-
+    uint64_t debug_size_in_bits = LLVMSizeOfTypeInBits(c->codegen->target_data_ref, struct_type->type_ref);
+    uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(c->codegen->target_data_ref, struct_type->type_ref);
     LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(c->codegen->dbuilder,
             LLVMZigFileToScope(c->import->di_file),
-            buf_ptr(full_type_name),
-            c->import->di_file, line + 1, struct_type->size_in_bits, struct_type->align_in_bits, 0,
+            buf_ptr(full_type_name), c->import->di_file, line + 1,
+            debug_size_in_bits,
+            debug_align_in_bits,
+            0,
             nullptr, di_element_types, field_count, 0, nullptr, "");
 
     LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
test/run_tests.cpp
@@ -379,10 +379,10 @@ pub fn main(args: [][]u8) -> %void {
     array[0] = void{};
     array[1] = array[2];
     if (@sizeof(@typeof(array)) != 0) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD sizeof\n");
     }
     if (array.len != 4) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD len\n");
     }
     %%stdout.printf("OK\n");
 }
@@ -1075,22 +1075,22 @@ pub fn main(args: [][]u8) -> %void {
     const bar = Bar.B;
 
     if (bar != Bar.B) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD 1\n");
     }
 
     if (@member_count(Foo) != 3) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD 2\n");
     }
 
     if (@member_count(Bar) != 4) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD 3\n");
     }
 
-    if (@sizeof(Foo) != 17) {
-        %%stdout.printf("BAD\n");
+    if (@sizeof(Foo) != 24) {
+        %%stdout.printf("BAD 4\n");
     }
     if (@sizeof(Bar) != 1) {
-        %%stdout.printf("BAD\n");
+        %%stdout.printf("BAD 5\n");
     }
 
     %%stdout.printf("OK\n");