From 5bc877017ede3b85361a112987757ee277b9c889 Mon Sep 17 00:00:00 2001 From: scurest Date: Sat, 17 Jun 2017 11:30:29 -0500 Subject: use most_aligned_member+padding to represent enum unions --- src/analyze.cpp | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) (limited to 'src/analyze.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 0b43f2d1e4..d233cd5a82 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(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); @@ -1272,7 +1273,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_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 debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); assert(debug_size_in_bits > 0); assert(debug_align_in_bits > 0); @@ -1285,13 +1286,14 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { 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, debug_size_in_bits); - if (!biggest_union_member || - debug_size_in_bits > biggest_union_member_size_in_bits) + if (!most_aligned_union_member || + debug_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 = debug_align_in_bits; + size_of_most_aligned_member_in_bits = debug_size_in_bits; } } @@ -1300,16 +1302,34 @@ 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) { + 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*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= + biggest_align_in_bits); + assert(8*LLVMABISizeOfType(g->target_data_ref, union_type_ref) >= + biggest_size_in_bits); // create llvm type for root struct LLVMTypeRef root_struct_element_types[] = { @@ -1331,7 +1351,7 @@ 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 @@ -1348,7 +1368,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { 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); @@ -2541,7 +2561,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, -- cgit v1.2.3 From 40feecb3e468ca9fc3b5bcbe4b0a4aa30d10f226 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 26 Aug 2017 13:51:51 -0400 Subject: fixups from previous commit See #396 --- src/analyze.cpp | 28 +++++++++++++--------------- test/cases/enum.zig | 6 ++++-- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src/analyze.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index d233cd5a82..bc9ee51ebb 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1272,28 +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*LLVMABIAlignmentOfType(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_size_in_bits = max(biggest_size_in_bits, debug_size_in_bits); + biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits); if (!most_aligned_union_member || - debug_align_in_bits > biggest_align_in_bits) + preferred_align_in_bits > biggest_align_in_bits) { most_aligned_union_member = field_type; - biggest_align_in_bits = debug_align_in_bits; - size_of_most_aligned_member_in_bits = debug_size_in_bits; + biggest_align_in_bits = preferred_align_in_bits; + size_of_most_aligned_member_in_bits = store_size_in_bits; } } @@ -1326,10 +1326,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { } enum_type->data.enumeration.union_type_ref = union_type_ref; - assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= - biggest_align_in_bits); - assert(8*LLVMABISizeOfType(g->target_data_ref, union_type_ref) >= - biggest_size_in_bits); + 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); // create llvm type for root struct LLVMTypeRef root_struct_element_types[] = { @@ -1340,7 +1338,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, ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum", import->di_file, (unsigned)(decl_node->line + 1), diff --git a/test/cases/enum.zig b/test/cases/enum.zig index 3cbd3afaa3..a07efaf61d 100644 --- a/test/cases/enum.zig +++ b/test/cases/enum.zig @@ -123,8 +123,10 @@ const BareNumber = enum { test "enum alignment" { - comptime assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); - comptime assert(@alignOf(AlignTestEnum) >= @alignOf(u64)); + comptime { + assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf([9]u8)); + assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf(u64)); + } } const AlignTestEnum = enum { -- cgit v1.2.3 From a0ae575ff8aef87d2dc4134c625f3a479b484b0f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 26 Aug 2017 14:25:52 -0400 Subject: codegen for enums chooses best order of tag and union fields closes #396 --- src/all_types.hpp | 6 +++--- src/analyze.cpp | 33 +++++++++++++++++++++------------ src/codegen.cpp | 20 ++++++++++++-------- 3 files changed, 36 insertions(+), 23 deletions(-) (limited to 'src/analyze.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 567e40d3ce..406b75db03 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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 { @@ -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; diff --git a/src/analyze.cpp b/src/analyze.cpp index bc9ee51ebb..3b4b933081 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1306,6 +1306,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); enum_type->data.enumeration.tag_type = tag_type_entry; + 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 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; @@ -1329,11 +1331,18 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { 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 @@ -1353,7 +1362,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { 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), @@ -1362,7 +1372,8 @@ 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), @@ -1372,11 +1383,9 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { 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); @@ -1396,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), diff --git a/src/codegen.cpp b/src/codegen.cpp index ac4f94e133..28f1887c9b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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), ""); @@ -3687,10 +3692,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } else { 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); } } -- cgit v1.2.3