mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 20:43:19 +00:00
parent
63d37b7cff
commit
1fc2082b4c
@ -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;
|
||||
|
||||
221
src/analyze.cpp
221
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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
167
src/codegen.cpp
167
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user