ability to declare const bitfields

See #261
This commit is contained in:
Andrew Kelley 2017-02-15 18:55:29 -05:00
parent 63d37b7cff
commit 1fc2082b4c
6 changed files with 370 additions and 86 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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");
}