Skip to content

Commit

Permalink
use llvm named structs for const values when possible
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
andrewrk committed Oct 27, 2017
1 parent 6663638 commit f1072d0
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 20 deletions.
3 changes: 3 additions & 0 deletions src/all_types.hpp
Expand Up @@ -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 {
Expand Down
7 changes: 3 additions & 4 deletions src/analyze.cpp
Expand Up @@ -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);
Expand All @@ -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;

Expand Down
85 changes: 69 additions & 16 deletions src/codegen.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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:
{
Expand All @@ -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:
{
Expand All @@ -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 {
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit f1072d0

Please sign in to comment.