Commit a0ae575ff8

Andrew Kelley <superjoe30@gmail.com>
2017-08-26 20:25:52
codegen for enums chooses best order of tag and union fields
closes #396
1 parent 40feecb
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;
 
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),
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);
                 }
             }