Commit f1072d0d9f

Andrew Kelley <superjoe30@gmail.com>
2017-10-24 08:14:55
use llvm named structs for const values when possible
normally we want to use llvm types for constants. but union constants (which are found inside enums) when they are initialized with the non-most-aligned-member must be unnamed structs. these bubble up to all aggregate types. if a constant of an aggregate type contains, recursively, a union constant with a non-most-aligned-member initialized, the aggregate typed constant must be unnamed too. this fixes some of the asserts that were coming in from llvm master branch.
1 parent 6663638
src/all_types.hpp
@@ -1008,6 +1008,9 @@ struct TypeTableEntryEnum {
 
     size_t gen_union_index;
     size_t gen_tag_index;
+
+    uint32_t union_size_bytes;
+    TypeTableEntry *most_aligned_union_member;
 };
 
 struct TypeTableEntryEnumTag {
src/analyze.cpp
@@ -1363,6 +1363,8 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
     // unset temporary flag
     enum_type->data.enumeration.embedded_in_current = false;
     enum_type->data.enumeration.complete = true;
+    enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
+    enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
 
     if (!enum_type->data.enumeration.is_invalid) {
         TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
@@ -1384,10 +1386,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
                 };
                 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);
+                union_type_ref = most_aligned_union_member->type_ref;
             }
             enum_type->data.enumeration.union_type_ref = union_type_ref;
 
src/codegen.cpp
@@ -3665,6 +3665,12 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
     zig_unreachable();
 }
 
+// We have this because union constants can't be represented by the official union type,
+// and this property bubbles up in whatever aggregate type contains a union constant
+static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef val) {
+    return LLVMTypeOf(val) != type_entry->type_ref;
+}
+
 static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
     TypeTableEntry *type_entry = const_val->type;
     assert(!type_entry->zero_bits);
@@ -3726,24 +3732,34 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                 } else {
                     LLVMValueRef child_val;
                     LLVMValueRef maybe_val;
+                    bool make_unnamed_struct;
                     if (const_val->data.x_maybe) {
                         child_val = gen_const_val(g, const_val->data.x_maybe);
                         maybe_val = LLVMConstAllOnes(LLVMInt1Type());
+
+                        make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val);
                     } else {
-                        child_val = LLVMConstNull(child_type->type_ref);
+                        child_val = LLVMGetUndef(child_type->type_ref);
                         maybe_val = LLVMConstNull(LLVMInt1Type());
+
+                        make_unnamed_struct = false;
                     }
                     LLVMValueRef fields[] = {
                         child_val,
                         maybe_val,
                     };
-                    return LLVMConstStruct(fields, 2, false);
+                    if (make_unnamed_struct) {
+                        return LLVMConstStruct(fields, 2, false);
+                    } else {
+                        return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                    }
                 }
             }
         case TypeTableEntryIdStruct:
             {
                 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
                 size_t src_field_count = type_entry->data.structure.src_field_count;
+                bool make_unnamed_struct = false;
                 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
                     size_t src_field_index = 0;
                     while (src_field_index < src_field_count) {
@@ -3761,8 +3777,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                         }
 
                         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]);
+                            ConstExprValue *field_val = &const_val->data.x_struct.fields[src_field_index];
+                            LLVMValueRef val = gen_const_val(g, field_val);
+                            fields[type_struct_field->gen_index] = val;
+                            make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
                         } else {
                             LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,
                                     (unsigned)type_struct_field->gen_index);
@@ -3790,11 +3808,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                         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]);
+                        ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
+                        LLVMValueRef val = gen_const_val(g, field_val);
+                        fields[type_struct_field->gen_index] = val;
+                        make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
                     }
                 }
-                return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count,
-                    type_entry->data.structure.layout == ContainerLayoutPacked);
+                if (make_unnamed_struct) {
+                    return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count,
+                        type_entry->data.structure.layout == ContainerLayoutPacked);
+                } else {
+                    return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
+                }
             }
         case TypeTableEntryIdUnion:
             {
@@ -3808,11 +3833,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                 }
 
                 LLVMValueRef *values = allocate<LLVMValueRef>(len);
+                LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref;
+                bool make_unnamed_struct = false;
                 for (uint64_t i = 0; i < len; i += 1) {
                     ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i];
-                    values[i] = gen_const_val(g, elem_value);
+                    LLVMValueRef val = gen_const_val(g, elem_value);
+                    values[i] = val;
+                    make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
+                }
+                if (make_unnamed_struct) {
+                    return LLVMConstStruct(values, len, true);
+                } else {
+                    return LLVMConstArray(element_type_ref, values, (unsigned)len);
                 }
-                return LLVMConstArray(LLVMTypeOf(values[0]), values, (unsigned)len);
             }
         case TypeTableEntryIdEnum:
             {
@@ -3825,14 +3858,20 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                     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;
+
+                    bool make_unnamed_struct;
+
                     if (type_has_bits(enum_field->type_entry)) {
-                        uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_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;
+                        uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes;
+
+                        ConstExprValue *payload_value = const_val->data.x_enum.payload;
+                        LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
+
+                        make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
+                            payload_value->type != type_entry->data.enumeration.most_aligned_union_member;
 
-                        LLVMValueRef correctly_typed_value = gen_const_val(g, const_val->data.x_enum.payload);
                         if (pad_bytes == 0) {
                             union_value = correctly_typed_value;
                         } else {
@@ -3843,12 +3882,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                             union_value = LLVMConstStruct(fields, 2, false);
                         }
                     } else {
+                        make_unnamed_struct = false;
                         union_value = LLVMGetUndef(union_type_ref);
                     }
                     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);
+
+                    if (make_unnamed_struct) {
+                        return LLVMConstStruct(fields, 2, false);
+                    } else {
+                        return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                    }
                 }
             }
         case TypeTableEntryIdFn:
@@ -3932,18 +3977,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
                 } else {
                     LLVMValueRef err_tag_value;
                     LLVMValueRef err_payload_value;
+                    bool make_unnamed_struct;
                     if (const_val->data.x_err_union.err) {
                         err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
                         err_payload_value = LLVMConstNull(child_type->type_ref);
+                        make_unnamed_struct = false;
                     } else {
                         err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
-                        err_payload_value = gen_const_val(g, const_val->data.x_err_union.payload);
+                        ConstExprValue *payload_val = const_val->data.x_err_union.payload;
+                        err_payload_value = gen_const_val(g, payload_val);
+                        make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
                     }
                     LLVMValueRef fields[] = {
                         err_tag_value,
                         err_payload_value,
                     };
-                    return LLVMConstStruct(fields, 2, false);
+                    if (make_unnamed_struct) {
+                        return LLVMConstStruct(fields, 2, false);
+                    } else {
+                        return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+                    }
                 }
             }
         case TypeTableEntryIdVoid: