Commit 1fc2082b4c

Andrew Kelley <superjoe30@gmail.com>
2017-02-16 00:55:29
ability to declare const bitfields
See #261
1 parent 63d37b7
src/all_types.hpp
@@ -873,11 +873,13 @@ struct TypeStructField {
     TypeTableEntry *type_entry;
     size_t src_index;
     size_t gen_index;
+    // offset from the memory at gen_index
+    size_t packed_bits_offset;
+    size_t packed_bits_size;
 };
 struct TypeTableEntryStruct {
     AstNode *decl_node;
     ContainerLayout layout;
-    bool is_packed;
     uint32_t src_field_count;
     uint32_t gen_field_count;
     TypeStructField *fields;
@@ -1037,7 +1039,7 @@ struct TypeTableEntry {
 
     // use these fields to make sure we don't duplicate type table entries for the same type
     TypeTableEntry *pointer_parent[2][2]; // [0 - mut, 1 - const][0 - normal, 1 - volatile]
-    TypeTableEntry *unknown_size_array_parent[2];
+    TypeTableEntry *slice_parent[2]; // [0 - mut, 1 - const]
     HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
     TypeTableEntry *maybe_parent;
     TypeTableEntry *error_parent;
@@ -1193,6 +1195,14 @@ enum PanicMsgId {
 uint32_t fn_eval_hash(Scope*);
 bool fn_eval_eql(Scope *a, Scope *b);
 
+struct IntTypeId {
+    bool is_signed;
+    uint8_t bit_count;
+};
+
+uint32_t int_type_id_hash(IntTypeId);
+bool int_type_id_eql(IntTypeId a, IntTypeId b);
+
 struct CodeGen {
     LLVMModuleRef module;
     ZigList<ErrorMsg*> errors;
@@ -1208,6 +1218,7 @@ struct CodeGen {
     HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
     HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
     HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
+    HashMap<IntTypeId, TypeTableEntry *, int_type_id_hash, int_type_id_eql> int_type_table;
     HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
     HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
     HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
src/analyze.cpp
@@ -261,6 +261,24 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
     }
 }
 
+// This has to do with packed structs
+static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
+    TypeTableEntry *canon_type = get_underlying_type(type_entry);
+
+    if (!type_has_bits(type_entry))
+        return 0;
+
+    if (canon_type->id == TypeTableEntryIdStruct && canon_type->data.structure.layout == ContainerLayoutPacked) {
+        uint64_t result = 0;
+        for (size_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) {
+            result += type_size_bits(g, canon_type->data.structure.fields[i].type_entry);
+        }
+        return result;
+    }
+
+    return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref);
+}
+
 static bool is_slice(TypeTableEntry *type) {
     return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
 }
@@ -507,7 +525,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
     TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
 
     unsigned element_count = 2;
-    entry->data.structure.is_packed = false;
+    entry->data.structure.layout = ContainerLayoutAuto;
     entry->data.structure.is_slice = true;
     entry->data.structure.src_field_count = element_count;
     entry->data.structure.gen_field_count = element_count;
@@ -531,7 +549,7 @@ static void slice_type_common_init(CodeGen *g, TypeTableEntry *child_type,
 
 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)];
+    TypeTableEntry **parent_pointer = &child_type->slice_parent[(is_const ? 1 : 0)];
 
     if (*parent_pointer) {
         return *parent_pointer;
@@ -1269,6 +1287,48 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
     }
 }
 
+static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
+    TypeTableEntry *canon_type = get_underlying_type(type_entry);
+    switch (canon_type->id) {
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdVar:
+            zig_unreachable();
+        case TypeTableEntryIdMetaType:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdNumLitFloat:
+        case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdUndefLit:
+        case TypeTableEntryIdNullLit:
+        case TypeTableEntryIdErrorUnion:
+        case TypeTableEntryIdPureError:
+        case TypeTableEntryIdEnum:
+        case TypeTableEntryIdEnumTag:
+        case TypeTableEntryIdTypeDecl:
+        case TypeTableEntryIdNamespace:
+        case TypeTableEntryIdBlock:
+        case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdArgTuple:
+            return false;
+        case TypeTableEntryIdVoid:
+        case TypeTableEntryIdBool:
+        case TypeTableEntryIdInt:
+        case TypeTableEntryIdFloat:
+        case TypeTableEntryIdPointer:
+        case TypeTableEntryIdArray:
+        case TypeTableEntryIdUnion:
+        case TypeTableEntryIdFn:
+            return true;
+        case TypeTableEntryIdStruct:
+            return canon_type->data.structure.layout == ContainerLayoutPacked;
+        case TypeTableEntryIdMaybe:
+            {
+                TypeTableEntry *canon_child_type = get_underlying_type(canon_type->data.maybe.child_type);
+                return canon_child_type->id == TypeTableEntryIdPointer || canon_child_type->id == TypeTableEntryIdFn;
+            }
+    }
+    zig_unreachable();
+}
+
 static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
     // if you change the logic of this function likely you must make a similar change in
     // parseh.cpp
@@ -1307,22 +1367,77 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
 
     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];
         TypeTableEntry *field_type = type_struct_field->type_entry;
 
         ensure_complete_type(g, field_type);
+
         if (type_is_invalid(field_type)) {
             struct_type->data.structure.is_invalid = true;
-            continue;
+            break;
         }
 
         if (!type_has_bits(field_type))
             continue;
 
-        element_types[type_struct_field->gen_index] = field_type->type_ref;
-        assert(element_types[type_struct_field->gen_index]);
+        type_struct_field->gen_index = gen_field_index;
+
+        if (packed) {
+            if (!type_allowed_in_packed_struct(field_type)) {
+                AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
+                add_node_error(g, field_source_node,
+                        buf_sprintf("packed structs cannot contain fields of type '%s'",
+                            buf_ptr(&field_type->name)));
+                struct_type->data.structure.is_invalid = true;
+                break;
+            }
+
+            type_struct_field->packed_bits_size = type_size_bits(g, field_type);
+
+            size_t next_packed_bits_offset = packed_bits_offset + type_struct_field->packed_bits_size;
+
+            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->packed_bits_offset = packed_bits_offset - first_packed_bits_offset_misalign;
+
+                if (next_packed_bits_offset % 8 == 0) {
+                    // next field recovers byte alignment
+                    size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
+                    element_types[gen_field_index] = LLVMIntType(full_bit_count);
+                    gen_field_index += 1;
+
+                    first_packed_bits_offset_misalign = SIZE_MAX;
+                }
+            } else if (next_packed_bits_offset % 8 != 0) {
+                first_packed_bits_offset_misalign = packed_bits_offset;
+                type_struct_field->packed_bits_offset = 0;
+            } else {
+                element_types[gen_field_index] = field_type->type_ref;
+                type_struct_field->packed_bits_offset = 0;
+                gen_field_index += 1;
+            }
+            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;
+        }
+        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;
+        element_types[gen_field_index] = LLVMIntType(full_bit_count);
+        gen_field_index += 1;
+    }
+
     struct_type->data.structure.embedded_in_current = false;
     struct_type->data.structure.complete = true;
 
@@ -1337,13 +1452,18 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
     }
     assert(struct_type->di_type);
 
-    bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
+
+    // the count may have been adjusting from packing bit fields
+    gen_field_count = gen_field_index;
+    struct_type->data.structure.gen_field_count = gen_field_count;
+
     LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, packed);
     assert(LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref) > 0);
 
-    ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(gen_field_count);
+    ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
 
     ImportTableEntry *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];
@@ -1369,19 +1489,28 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
         assert(field_type->type_ref);
         assert(struct_type->type_ref);
         assert(struct_type->data.structure.complete);
-        uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(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] = ZigLLVMCreateDebugMemberType(g->dbuilder,
+        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->packed_bits_size;
+            debug_align_in_bits = 1;
+            debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref,
+                    gen_field_index) + type_struct_field->packed_bits_offset;
+        } 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, gen_field_index);
+        }
+        di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
                 ZigLLVMTypeToScope(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_di_type);
-
-        assert(di_element_types[gen_field_index]);
+        assert(di_element_types[debug_field_index]);
+        debug_field_index += 1;
     }
 
 
@@ -1393,7 +1522,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
             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, "");
+            0, nullptr, di_element_types, debug_field_count, 0, nullptr, "");
 
     ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
     struct_type->di_type = replacement_di_type;
@@ -2672,7 +2801,7 @@ bool is_node_void_expr(AstNode *node) {
     return false;
 }
 
-TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits) {
+TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits) {
     size_t index;
     if (size_in_bits == 8) {
         index = 0;
@@ -2683,13 +2812,25 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bit
     } else if (size_in_bits == 64) {
         index = 3;
     } else {
-        zig_unreachable();
+        return nullptr;
     }
     return &g->builtin_types.entry_int[is_signed ? 0 : 1][index];
 }
 
-TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) {
-    return *get_int_type_ptr(g, is_signed, size_in_bits);
+TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits) {
+    TypeTableEntry **common_entry = get_int_type_ptr(g, is_signed, size_in_bits);
+    if (common_entry)
+        return *common_entry;
+
+    {
+        auto entry = g->int_type_table.maybe_get({is_signed, size_in_bits});
+        if (entry)
+            return entry->value;
+    }
+
+    TypeTableEntry *new_entry = make_int_type(g, is_signed, size_in_bits);
+    g->int_type_table.put({is_signed, size_in_bits}, new_entry);
+    return new_entry;
 }
 
 TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) {
@@ -3703,3 +3844,45 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
     }
     zig_unreachable();
 }
+
+TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits) {
+    TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
+    entry->type_ref = LLVMIntType(size_in_bits);
+
+    const char u_or_i = is_signed ? 'i' : 'u';
+    buf_resize(&entry->name, 0);
+    buf_appendf(&entry->name, "%c%zu", 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 = 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->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
+            debug_size_in_bits, debug_align_in_bits, dwarf_tag);
+    entry->data.integral.is_signed = is_signed;
+    entry->data.integral.bit_count = size_in_bits;
+    return entry;
+}
+
+uint32_t int_type_id_hash(IntTypeId x) {
+    uint32_t hash = x.is_signed ? 2652528194 : 163929201;
+    hash += ((uint32_t)x.bit_count) * 2998081557;
+    return hash;
+}
+
+bool int_type_id_eql(IntTypeId a, IntTypeId b) {
+    return (a.is_signed == b.is_signed && a.bit_count == b.bit_count);
+}
src/analyze.hpp
@@ -18,8 +18,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
 TypeTableEntry *get_pointer_to_type_volatile(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_volatile);
 bool is_node_void_expr(AstNode *node);
 uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
-TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, size_t size_in_bits);
-TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits);
+TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits);
+TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits);
 TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
 TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
 TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
@@ -143,4 +143,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
 
 void init_const_undefined(CodeGen *g, ConstExprValue *const_val);
 
+TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits);
+
 #endif
src/bignum.cpp
@@ -46,42 +46,35 @@ void bignum_init_bignum(BigNum *dest, BigNum *src) {
     safe_memcpy(dest, src, 1);
 }
 
+static int u64_log2(uint64_t x) {
+    int result = 0;
+    for (; x != 0; x >>= 1) {
+        result += 1;
+    }
+    return result;
+}
+
 bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
     assert(bn->kind == BigNumKindInt);
 
     if (is_signed) {
-        if (bn->is_negative) {
-            if (bn->data.x_uint <= ((uint64_t)INT8_MAX) + 1) {
-                return bit_count >= 8;
-            } else if (bn->data.x_uint <= ((uint64_t)INT16_MAX) + 1) {
-                return bit_count >= 16;
-            } else if (bn->data.x_uint <= ((uint64_t)INT32_MAX) + 1) {
-                return bit_count >= 32;
-            } else {
-                return bit_count >= 64;
-            }
-        } else if (bn->data.x_uint <= (uint64_t)INT8_MAX) {
-            return bit_count >= 8;
-        } else if (bn->data.x_uint <= (uint64_t)INT16_MAX) {
-            return bit_count >= 16;
-        } else if (bn->data.x_uint <= (uint64_t)INT32_MAX) {
-            return bit_count >= 32;
+        uint64_t max_neg;
+        uint64_t max_pos;
+        if (bit_count < 64) {
+            max_neg = (1ULL << (bit_count - 1));
+            max_pos = max_neg - 1;
         } else {
-            return bit_count >= 64;
+            max_pos = ((uint64_t)INT64_MAX);
+            max_neg = max_pos + 1;
         }
+        uint64_t max_val = bn->is_negative ? max_neg : max_pos;
+        return bn->data.x_uint <= max_val;
     } else {
         if (bn->is_negative) {
             return bn->data.x_uint == 0;
         } else {
-            if (bn->data.x_uint <= UINT8_MAX) {
-                return bit_count >= 8;
-            } else if (bn->data.x_uint <= UINT16_MAX) {
-                return bit_count >= 16;
-            } else if (bn->data.x_uint <= UINT32_MAX) {
-                return bit_count >= 32;
-            } else {
-                return bit_count >= 64;
-            }
+            int required_bit_count = u64_log2(bn->data.x_uint);
+            return bit_count >= required_bit_count;
         }
     }
 }
src/codegen.cpp
@@ -58,6 +58,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
     g->import_table.init(32);
     g->builtin_fn_table.init(32);
     g->primitive_type_table.init(32);
+    g->int_type_table.init(8);
     g->fn_type_table.init(32);
     g->error_table.init(16);
     g->generic_table.init(16);
@@ -232,6 +233,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script) {
 
 static void render_const_val(CodeGen *g, ConstExprValue *const_val);
 static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name);
+static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val);
 
 static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
     if (fn_table_entry->llvm_value)
@@ -2599,6 +2601,84 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
     return LLVMConstInBoundsGEP(base_ptr, indices, 2);
 }
 
+static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { 
+    switch (const_val->special) {
+        case ConstValSpecialRuntime:
+            zig_unreachable();
+        case ConstValSpecialUndef:
+            return LLVMConstInt(big_int_type_ref, 0, false);
+        case ConstValSpecialStatic:
+            break;
+    }
+
+    TypeTableEntry *canon_type = get_underlying_type(const_val->type);
+    assert(!canon_type->zero_bits);
+    switch (canon_type->id) {
+        case TypeTableEntryIdInvalid:
+        case TypeTableEntryIdVar:
+        case TypeTableEntryIdMetaType:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdNumLitFloat:
+        case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdUndefLit:
+        case TypeTableEntryIdNullLit:
+        case TypeTableEntryIdErrorUnion:
+        case TypeTableEntryIdPureError:
+        case TypeTableEntryIdEnum:
+        case TypeTableEntryIdEnumTag:
+        case TypeTableEntryIdTypeDecl:
+        case TypeTableEntryIdNamespace:
+        case TypeTableEntryIdBlock:
+        case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdArgTuple:
+        case TypeTableEntryIdVoid:
+            zig_unreachable();
+        case TypeTableEntryIdBool:
+            return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false);
+        case TypeTableEntryIdInt:
+            {
+                LLVMValueRef int_val = gen_const_val(g, const_val);
+                return LLVMConstZExt(int_val, big_int_type_ref);
+            }
+            return LLVMConstInt(big_int_type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
+        case TypeTableEntryIdFloat:
+            {
+                LLVMValueRef float_val = gen_const_val(g, const_val);
+                LLVMValueRef int_val = LLVMConstFPToUI(float_val, LLVMIntType(canon_type->data.floating.bit_count));
+                return LLVMConstZExt(int_val, big_int_type_ref);
+            }
+        case TypeTableEntryIdPointer:
+        case TypeTableEntryIdFn:
+        case TypeTableEntryIdMaybe:
+            {
+                LLVMValueRef ptr_val = gen_const_val(g, const_val);
+                LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
+                return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);
+            }
+        case TypeTableEntryIdArray:
+            zig_panic("TODO bit pack an array");
+        case TypeTableEntryIdUnion:
+            zig_panic("TODO bit pack a union");
+        case TypeTableEntryIdStruct:
+            {
+                assert(canon_type->data.structure.layout == ContainerLayoutPacked);
+
+                LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
+                for (size_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) {
+                    TypeStructField *field = &canon_type->data.structure.fields[i];
+                    if (field->gen_index == SIZE_MAX) {
+                        continue;
+                    }
+                    LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]);
+                    LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);
+                    val = LLVMConstShl(val, shift_amt);
+                    val = LLVMConstOr(val, child_val);
+                }
+                return val;
+            }
+    }
+    zig_unreachable();
+}
 
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
     TypeTableEntry *canon_type = get_underlying_type(const_val->type);
@@ -2670,15 +2750,57 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
         case TypeTableEntryIdStruct:
             {
                 LLVMValueRef *fields = allocate<LLVMValueRef>(canon_type->data.structure.gen_field_count);
-                for (uint32_t i = 0; i < canon_type->data.structure.src_field_count; i += 1) {
-                    TypeStructField *type_struct_field = &canon_type->data.structure.fields[i];
-                    if (type_struct_field->gen_index == SIZE_MAX) {
-                        continue;
+                size_t src_field_count = canon_type->data.structure.src_field_count;
+                if (canon_type->data.structure.layout == ContainerLayoutPacked) {
+                    size_t src_field_index = 0;
+                    while (src_field_index < src_field_count) {
+                        TypeStructField *type_struct_field = &canon_type->data.structure.fields[src_field_index];
+                        if (type_struct_field->gen_index == SIZE_MAX) {
+                            src_field_index += 1;
+                            continue;
+                        }
+
+                        size_t src_field_index_end = src_field_index + 1;
+                        for (; src_field_index_end < src_field_count; src_field_index_end += 1) {
+                            TypeStructField *it_field = &canon_type->data.structure.fields[src_field_index_end];
+                            if (it_field->gen_index != type_struct_field->gen_index)
+                                break;
+                        }
+
+                        if (src_field_index + 1 == src_field_index_end) {
+                            fields[type_struct_field->gen_index] =
+                                gen_const_val(g, &const_val->data.x_struct.fields[src_field_index]);
+                        } else {
+                            LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(canon_type->type_ref,
+                                    type_struct_field->gen_index);
+                            LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
+                            for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
+                                TypeStructField *it_field = &canon_type->data.structure.fields[i];
+                                if (it_field->gen_index == SIZE_MAX) {
+                                    continue;
+                                }
+                                LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,
+                                        &const_val->data.x_struct.fields[i]);
+                                LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
+                                        it_field->packed_bits_size, false);
+                                val = LLVMConstShl(val, shift_amt);
+                                val = LLVMConstOr(val, child_val);
+                            }
+                            fields[type_struct_field->gen_index] = val;
+                        }
+
+                        src_field_index = src_field_index_end;
+                    }
+                } else {
+                    for (uint32_t i = 0; i < src_field_count; i += 1) {
+                        TypeStructField *type_struct_field = &canon_type->data.structure.fields[i];
+                        if (type_struct_field->gen_index == SIZE_MAX) {
+                            continue;
+                        }
+                        fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]);
                     }
-                    fields[type_struct_field->gen_index] = gen_const_val(g, &const_val->data.x_struct.fields[i]);
                 }
-                return LLVMConstNamedStruct(canon_type->type_ref, fields,
-                        canon_type->data.structure.gen_field_count);
+                return LLVMConstNamedStruct(canon_type->type_ref, fields, canon_type->data.structure.gen_field_count);
             }
         case TypeTableEntryIdUnion:
             {
@@ -3406,37 +3528,8 @@ static void define_builtin_types(CodeGen *g) {
         size_t size_in_bits = int_sizes_in_bits[int_size_i];
         for (size_t is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) {
             bool is_signed = is_signed_list[is_sign_i];
-
-            TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
-            entry->type_ref = LLVMIntType(size_in_bits);
-
-            const char u_or_i = is_signed ? 'i' : 'u';
-            buf_resize(&entry->name, 0);
-            buf_appendf(&entry->name, "%c%zu", 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 = 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->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
-                    debug_size_in_bits, debug_align_in_bits, dwarf_tag);
-            entry->data.integral.is_signed = is_signed;
-            entry->data.integral.bit_count = size_in_bits;
+            TypeTableEntry *entry = make_int_type(g, is_signed, size_in_bits);
             g->primitive_type_table.put(&entry->name, entry);
-
             get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
         }
     }
test/run_tests.cpp
@@ -2212,6 +2212,7 @@ static void run_all_tests(bool reverse) {
         for (size_t i = test_cases.length;;) {
             TestCase *test_case = test_cases.at(i);
             printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
+            fflush(stdout);
             run_test(test_case);
             printf("OK\n");
             if (i == 0) break;
@@ -2221,6 +2222,7 @@ static void run_all_tests(bool reverse) {
         for (size_t i = 0; i < test_cases.length; i += 1) {
             TestCase *test_case = test_cases.at(i);
             printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
+            fflush(stdout);
             run_test(test_case);
             printf("OK\n");
         }