Commit 1fc2082b4c
Changed files (6)
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");
}