mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge branch 'align'
This commit is contained in:
commit
95aed8c457
@ -977,7 +977,7 @@ struct TypeTableEntryEnum {
|
||||
TypeEnumField *fields;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
TypeTableEntry *tag_type;
|
||||
TypeTableEntry *union_type;
|
||||
LLVMTypeRef union_type_ref;
|
||||
|
||||
ScopeDecls *decls_scope;
|
||||
|
||||
@ -989,6 +989,9 @@ struct TypeTableEntryEnum {
|
||||
|
||||
bool zero_bits_loop_flag;
|
||||
bool zero_bits_known;
|
||||
|
||||
size_t gen_union_index;
|
||||
size_t gen_tag_index;
|
||||
};
|
||||
|
||||
struct TypeTableEntryEnumTag {
|
||||
@ -1633,7 +1636,7 @@ struct ScopeDecls {
|
||||
struct ScopeBlock {
|
||||
Scope base;
|
||||
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
bool safety_off;
|
||||
AstNode *safety_set_node;
|
||||
bool fast_math_off;
|
||||
@ -2626,9 +2629,6 @@ static const size_t slice_len_index = 1;
|
||||
static const size_t maybe_child_index = 0;
|
||||
static const size_t maybe_null_index = 1;
|
||||
|
||||
static const size_t enum_gen_tag_index = 0;
|
||||
static const size_t enum_gen_union_index = 1;
|
||||
|
||||
static const size_t err_union_err_index = 0;
|
||||
static const size_t err_union_payload_index = 1;
|
||||
|
||||
|
||||
@ -1245,9 +1245,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;
|
||||
ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
|
||||
|
||||
TypeTableEntry *biggest_union_member = nullptr;
|
||||
TypeTableEntry *most_aligned_union_member = nullptr;
|
||||
uint64_t size_of_most_aligned_member_in_bits = 0;
|
||||
uint64_t biggest_align_in_bits = 0;
|
||||
uint64_t biggest_union_member_size_in_bits = 0;
|
||||
uint64_t biggest_size_in_bits = 0;
|
||||
|
||||
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
|
||||
ImportTableEntry *import = get_scope_import(scope);
|
||||
@ -1271,27 +1272,28 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
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 store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
|
||||
uint64_t preferred_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, field_type->type_ref);
|
||||
|
||||
assert(debug_size_in_bits > 0);
|
||||
assert(debug_align_in_bits > 0);
|
||||
assert(store_size_in_bits > 0);
|
||||
assert(preferred_align_in_bits > 0);
|
||||
|
||||
union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
|
||||
import->di_file, (unsigned)(field_node->line + 1),
|
||||
debug_size_in_bits,
|
||||
debug_align_in_bits,
|
||||
store_size_in_bits,
|
||||
preferred_align_in_bits,
|
||||
0,
|
||||
0, field_type->di_type);
|
||||
|
||||
biggest_align_in_bits = max(biggest_align_in_bits, debug_align_in_bits);
|
||||
biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
|
||||
|
||||
if (!biggest_union_member ||
|
||||
debug_size_in_bits > biggest_union_member_size_in_bits)
|
||||
if (!most_aligned_union_member ||
|
||||
preferred_align_in_bits > biggest_align_in_bits)
|
||||
{
|
||||
biggest_union_member = field_type;
|
||||
biggest_union_member_size_in_bits = debug_size_in_bits;
|
||||
most_aligned_union_member = field_type;
|
||||
biggest_align_in_bits = preferred_align_in_bits;
|
||||
size_of_most_aligned_member_in_bits = store_size_in_bits;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1300,27 +1302,52 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.complete = true;
|
||||
|
||||
if (!enum_type->data.enumeration.is_invalid) {
|
||||
enum_type->data.enumeration.union_type = biggest_union_member;
|
||||
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
if (biggest_union_member) {
|
||||
uint64_t align_of_tag_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
|
||||
if (most_aligned_union_member) {
|
||||
// create llvm type for union
|
||||
LLVMTypeRef union_element_type = biggest_union_member->type_ref;
|
||||
LLVMTypeRef union_type_ref = LLVMStructType(&union_element_type, 1, false);
|
||||
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
|
||||
LLVMTypeRef union_type_ref;
|
||||
if (padding_in_bits > 0) {
|
||||
TypeTableEntry *u8_type = get_int_type(g, false, 8);
|
||||
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
|
||||
LLVMTypeRef union_element_types[] = {
|
||||
most_aligned_union_member->type_ref,
|
||||
padding_array->type_ref,
|
||||
};
|
||||
union_type_ref = LLVMStructType(union_element_types, 2, false);
|
||||
} else {
|
||||
LLVMTypeRef union_element_types[] = {
|
||||
most_aligned_union_member->type_ref,
|
||||
};
|
||||
union_type_ref = LLVMStructType(union_element_types, 1, false);
|
||||
}
|
||||
enum_type->data.enumeration.union_type_ref = union_type_ref;
|
||||
|
||||
assert(8*LLVMPreferredAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
|
||||
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
|
||||
|
||||
if (align_of_tag_in_bits >= biggest_align_in_bits) {
|
||||
enum_type->data.enumeration.gen_tag_index = 0;
|
||||
enum_type->data.enumeration.gen_union_index = 1;
|
||||
} else {
|
||||
enum_type->data.enumeration.gen_union_index = 0;
|
||||
enum_type->data.enumeration.gen_tag_index = 1;
|
||||
}
|
||||
|
||||
// create llvm type for root struct
|
||||
LLVMTypeRef root_struct_element_types[] = {
|
||||
tag_type_entry->type_ref,
|
||||
union_type_ref,
|
||||
};
|
||||
LLVMTypeRef root_struct_element_types[2];
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
|
||||
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
|
||||
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
@ -1331,11 +1358,12 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
biggest_union_member_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
|
||||
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
|
||||
gen_field_count, 0, "");
|
||||
|
||||
// create debug types for members of root struct
|
||||
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 0);
|
||||
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_tag_index);
|
||||
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
@ -1344,21 +1372,20 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
tag_offset_in_bits,
|
||||
0, tag_di_type);
|
||||
|
||||
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 1);
|
||||
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_union_index);
|
||||
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "union_field",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
biggest_union_member_size_in_bits,
|
||||
biggest_size_in_bits,
|
||||
biggest_align_in_bits,
|
||||
union_offset_in_bits,
|
||||
0, union_di_type);
|
||||
|
||||
// create debug type for root struct
|
||||
ZigLLVMDIType *di_root_members[] = {
|
||||
tag_member_di_type,
|
||||
union_member_di_type,
|
||||
};
|
||||
|
||||
ZigLLVMDIType *di_root_members[2];
|
||||
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
|
||||
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
@ -1378,7 +1405,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
@ -2541,7 +2568,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
|
||||
if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
|
||||
return false;
|
||||
}
|
||||
if (!expected_type->data.fn.is_generic &&
|
||||
if (!expected_type->data.fn.is_generic &&
|
||||
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
|
||||
!types_match_const_cast_only(
|
||||
expected_type->data.fn.fn_type_id.return_type,
|
||||
|
||||
@ -2250,6 +2250,11 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
|
||||
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionEnumFieldPtr *instruction)
|
||||
{
|
||||
TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type;
|
||||
assert(enum_ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type;
|
||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
TypeEnumField *field = instruction->field;
|
||||
|
||||
if (!type_has_bits(field->type_entry))
|
||||
@ -2257,7 +2262,7 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl
|
||||
|
||||
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
|
||||
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
|
||||
|
||||
return bitcasted_union_field_ptr;
|
||||
@ -3112,7 +3117,7 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
|
||||
if (enum_type->data.enumeration.gen_field_count == 0)
|
||||
return enum_val;
|
||||
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_gen_tag_index, "");
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
|
||||
return get_handle_value(g, tag_field_ptr, tag_type, false);
|
||||
}
|
||||
|
||||
@ -3127,13 +3132,13 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
|
||||
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_tag_index, "");
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, "");
|
||||
LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
|
||||
|
||||
TypeTableEntry *union_val_type = instruction->field->type_entry;
|
||||
if (type_has_bits(union_val_type)) {
|
||||
LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_union_index, "");
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
|
||||
LLVMPointerType(union_val_type->type_ref, 0), "");
|
||||
|
||||
@ -3663,13 +3668,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
if (type_entry->data.enumeration.gen_field_count == 0) {
|
||||
return tag_value;
|
||||
} else {
|
||||
TypeTableEntry *union_type = type_entry->data.enumeration.union_type;
|
||||
LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
|
||||
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
|
||||
assert(enum_field->value == const_val->data.x_enum.tag);
|
||||
LLVMValueRef union_value;
|
||||
if (type_has_bits(enum_field->type_entry)) {
|
||||
uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
|
||||
union_type->type_ref);
|
||||
union_type_ref);
|
||||
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
|
||||
enum_field->type_entry->type_ref);
|
||||
uint64_t pad_bytes = union_type_bytes - field_type_bytes;
|
||||
@ -3685,12 +3690,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
union_value = LLVMConstStruct(fields, 2, false);
|
||||
}
|
||||
} else {
|
||||
union_value = LLVMGetUndef(union_type->type_ref);
|
||||
union_value = LLVMGetUndef(union_type_ref);
|
||||
}
|
||||
LLVMValueRef fields[] = {
|
||||
tag_value,
|
||||
union_value,
|
||||
};
|
||||
LLVMValueRef fields[2];
|
||||
fields[type_entry->data.enumeration.gen_tag_index] = tag_value;
|
||||
fields[type_entry->data.enumeration.gen_union_index] = union_value;
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,3 +120,16 @@ const BareNumber = enum {
|
||||
Two,
|
||||
Three,
|
||||
};
|
||||
|
||||
|
||||
test "enum alignment" {
|
||||
comptime {
|
||||
assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf([9]u8));
|
||||
assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf(u64));
|
||||
}
|
||||
}
|
||||
|
||||
const AlignTestEnum = enum {
|
||||
A: [9]u8,
|
||||
B: u64,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user