Commit f1072d0d9f
Changed files (3)
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: