diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-02-15 18:55:29 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-02-15 18:55:29 -0500 |
| commit | 1fc2082b4ccc2b75fba892bc9e27e9a5a3d821bf (patch) | |
| tree | 1c63bda773e97c41bcbdfd68d3d880ef46c0bd8d /src | |
| parent | 63d37b7cff0907cdf2361f1d61f19410fd6cc626 (diff) | |
| download | zig-1fc2082b4ccc2b75fba892bc9e27e9a5a3d821bf.tar.gz zig-1fc2082b4ccc2b75fba892bc9e27e9a5a3d821bf.zip | |
ability to declare const bitfields
See #261
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 15 | ||||
| -rw-r--r-- | src/analyze.cpp | 221 | ||||
| -rw-r--r-- | src/analyze.hpp | 6 | ||||
| -rw-r--r-- | src/bignum.cpp | 45 | ||||
| -rw-r--r-- | src/codegen.cpp | 167 |
5 files changed, 368 insertions, 86 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 5e2a275b22..051d9c3649 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/analyze.cpp b/src/analyze.cpp index f567502c29..f4a0dd20c7 100644 --- a/src/analyze.cpp +++ b/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); +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 3ef0696be3..406e1e5d81 100644 --- a/src/analyze.hpp +++ b/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 diff --git a/src/bignum.cpp b/src/bignum.cpp index e3b661e81a..9723b50994 100644 --- a/src/bignum.cpp +++ b/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; } } } diff --git a/src/codegen.cpp b/src/codegen.cpp index df4b6fcf7c..c13bd56f53 100644 --- a/src/codegen.cpp +++ b/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; } } |
