diff options
| -rw-r--r-- | src/all_types.hpp | 3 | ||||
| -rw-r--r-- | src/analyze.cpp | 7 | ||||
| -rw-r--r-- | src/codegen.cpp | 85 |
3 files changed, 75 insertions, 20 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index b8966e764a..9f59ae2aac 100644 --- a/src/all_types.hpp +++ b/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 { diff --git a/src/analyze.cpp b/src/analyze.cpp index e6ccf82dfe..89ce5df6b4 100644 --- a/src/analyze.cpp +++ b/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; diff --git a/src/codegen.cpp b/src/codegen.cpp index 68fd4159bd..0a78ef0740 100644 --- a/src/codegen.cpp +++ b/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: |
