aboutsummaryrefslogtreecommitdiff
path: root/src/analyze.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-26 14:26:43 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-26 14:26:43 -0400
commit95aed8c4575dc6f70e4368b9db527c6cec12acfa (patch)
treed7442193c336b49eb5a84a477a521ab85ad7d57f /src/analyze.cpp
parente726925e802eddab53cbfd9aacbc5eefe95c356f (diff)
parenta0ae575ff8aef87d2dc4134c625f3a479b484b0f (diff)
downloadzig-95aed8c4575dc6f70e4368b9db527c6cec12acfa.tar.gz
zig-95aed8c4575dc6f70e4368b9db527c6cec12acfa.zip
Merge branch 'align'
Diffstat (limited to 'src/analyze.cpp')
-rw-r--r--src/analyze.cpp95
1 files changed, 61 insertions, 34 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 0b43f2d1e4..3b4b933081 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -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,