codegen for enums chooses best order of tag and union fields

closes #396
master
Andrew Kelley 2017-08-26 14:25:52 -04:00
parent 40feecb3e4
commit a0ae575ff8
3 changed files with 36 additions and 23 deletions

View File

@ -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;

View File

@ -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),

View File

@ -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);
}
}