authorgravatar for scurest@users.noreply.github.comscurest <scurest@users.noreply.github.com> 2017-06-17 11:30:29-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-26 13:48:16-04:00
log5bc877017ede3b85361a112987757ee277b9c889
tree1403967c72b47399b0d2f796922007e350d14dda
parente726925e802eddab53cbfd9aacbc5eefe95c356f

use most_aligned_member+padding to represent enum unions


4 files changed, 52 insertions(+), 21 deletions(-)

src/all_types.hpp+2-2
...@@ -977,7 +977,7 @@ struct TypeTableEntryEnum {...@@ -977,7 +977,7 @@ struct TypeTableEntryEnum {
977 TypeEnumField *fields;977 TypeEnumField *fields;
978 bool is_invalid; // true if any fields are invalid978 bool is_invalid; // true if any fields are invalid
979 TypeTableEntry *tag_type;979 TypeTableEntry *tag_type;
980 TypeTableEntry *union_type;980 LLVMTypeRef union_type_ref;
981981
982 ScopeDecls *decls_scope;982 ScopeDecls *decls_scope;
983983
...@@ -1633,7 +1633,7 @@ struct ScopeDecls {...@@ -1633,7 +1633,7 @@ struct ScopeDecls {
1633struct ScopeBlock {1633struct ScopeBlock {
1634 Scope base;1634 Scope base;
16351635
1636 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; 1636 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
1637 bool safety_off;1637 bool safety_off;
1638 AstNode *safety_set_node;1638 AstNode *safety_set_node;
1639 bool fast_math_off;1639 bool fast_math_off;
src/analyze.cpp+36-16
...@@ -1245,9 +1245,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1245,9 +1245,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1245 uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;1245 uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;
1246 ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);1246 ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
12471247
1248 TypeTableEntry *biggest_union_member = nullptr;1248 TypeTableEntry *most_aligned_union_member = nullptr;
1249 uint64_t size_of_most_aligned_member_in_bits = 0;
1249 uint64_t biggest_align_in_bits = 0;1250 uint64_t biggest_align_in_bits = 0;
1250 uint64_t biggest_union_member_size_in_bits = 0;1251 uint64_t biggest_size_in_bits = 0;
12511252
1252 Scope *scope = &enum_type->data.enumeration.decls_scope->base;1253 Scope *scope = &enum_type->data.enumeration.decls_scope->base;
1253 ImportTableEntry *import = get_scope_import(scope);1254 ImportTableEntry *import = get_scope_import(scope);
...@@ -1272,7 +1273,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1272,7 +1273,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1272 continue;1273 continue;
12731274
1274 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);1275 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
1275 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, field_type->type_ref);1276 uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
12761277
1277 assert(debug_size_in_bits > 0);1278 assert(debug_size_in_bits > 0);
1278 assert(debug_align_in_bits > 0);1279 assert(debug_align_in_bits > 0);
...@@ -1285,13 +1286,14 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1285,13 +1286,14 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1285 0,1286 0,
1286 0, field_type->di_type);1287 0, field_type->di_type);
12871288
1288 biggest_align_in_bits = max(biggest_align_in_bits, debug_align_in_bits);1289 biggest_size_in_bits = max(biggest_size_in_bits, debug_size_in_bits);
12891290
1290 if (!biggest_union_member ||1291 if (!most_aligned_union_member ||
1291 debug_size_in_bits > biggest_union_member_size_in_bits)1292 debug_align_in_bits > biggest_align_in_bits)
1292 {1293 {
1293 biggest_union_member = field_type;1294 most_aligned_union_member = field_type;
1294 biggest_union_member_size_in_bits = debug_size_in_bits;1295 biggest_align_in_bits = debug_align_in_bits;
1296 size_of_most_aligned_member_in_bits = debug_size_in_bits;
1295 }1297 }
1296 }1298 }
12971299
...@@ -1300,16 +1302,34 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1300,16 +1302,34 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1300 enum_type->data.enumeration.complete = true;1302 enum_type->data.enumeration.complete = true;
13011303
1302 if (!enum_type->data.enumeration.is_invalid) {1304 if (!enum_type->data.enumeration.is_invalid) {
1303 enum_type->data.enumeration.union_type = biggest_union_member;
1304
1305 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);1305 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1306 TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);1306 TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1307 enum_type->data.enumeration.tag_type = tag_type_entry;1307 enum_type->data.enumeration.tag_type = tag_type_entry;
13081308
1309 if (biggest_union_member) {1309 if (most_aligned_union_member) {
1310 // create llvm type for union1310 // create llvm type for union
1311 LLVMTypeRef union_element_type = biggest_union_member->type_ref;1311 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1312 LLVMTypeRef union_type_ref = LLVMStructType(&union_element_type, 1, false);1312 LLVMTypeRef union_type_ref;
1313 if (padding_in_bits > 0) {
1314 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1315 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1316 LLVMTypeRef union_element_types[] = {
1317 most_aligned_union_member->type_ref,
1318 padding_array->type_ref,
1319 };
1320 union_type_ref = LLVMStructType(union_element_types, 2, false);
1321 } else {
1322 LLVMTypeRef union_element_types[] = {
1323 most_aligned_union_member->type_ref,
1324 };
1325 union_type_ref = LLVMStructType(union_element_types, 1, false);
1326 }
1327 enum_type->data.enumeration.union_type_ref = union_type_ref;
1328
1329 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >=
1330 biggest_align_in_bits);
1331 assert(8*LLVMABISizeOfType(g->target_data_ref, union_type_ref) >=
1332 biggest_size_in_bits);
13131333
1314 // create llvm type for root struct1334 // create llvm type for root struct
1315 LLVMTypeRef root_struct_element_types[] = {1335 LLVMTypeRef root_struct_element_types[] = {
...@@ -1331,7 +1351,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1331,7 +1351,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1331 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,1351 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1332 ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",1352 ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
1333 import->di_file, (unsigned)(decl_node->line + 1),1353 import->di_file, (unsigned)(decl_node->line + 1),
1334 biggest_union_member_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,1354 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1335 gen_field_count, 0, "");1355 gen_field_count, 0, "");
13361356
1337 // create debug types for members of root struct1357 // create debug types for members of root struct
...@@ -1348,7 +1368,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1348,7 +1368,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1348 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,1368 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1349 ZigLLVMTypeToScope(enum_type->di_type), "union_field",1369 ZigLLVMTypeToScope(enum_type->di_type), "union_field",
1350 import->di_file, (unsigned)(decl_node->line + 1),1370 import->di_file, (unsigned)(decl_node->line + 1),
1351 biggest_union_member_size_in_bits,1371 biggest_size_in_bits,
1352 biggest_align_in_bits,1372 biggest_align_in_bits,
1353 union_offset_in_bits,1373 union_offset_in_bits,
1354 0, union_di_type);1374 0, union_di_type);
...@@ -2541,7 +2561,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *...@@ -2541,7 +2561,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
2541 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {2561 if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
2542 return false;2562 return false;
2543 }2563 }
2544 if (!expected_type->data.fn.is_generic && 2564 if (!expected_type->data.fn.is_generic &&
2545 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&2565 actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
2546 !types_match_const_cast_only(2566 !types_match_const_cast_only(
2547 expected_type->data.fn.fn_type_id.return_type,2567 expected_type->data.fn.fn_type_id.return_type,
src/codegen.cpp+3-3
...@@ -3663,13 +3663,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3663,13 +3663,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3663 if (type_entry->data.enumeration.gen_field_count == 0) {3663 if (type_entry->data.enumeration.gen_field_count == 0) {
3664 return tag_value;3664 return tag_value;
3665 } else {3665 } else {
3666 TypeTableEntry *union_type = type_entry->data.enumeration.union_type;3666 LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
3667 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];3667 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
3668 assert(enum_field->value == const_val->data.x_enum.tag);3668 assert(enum_field->value == const_val->data.x_enum.tag);
3669 LLVMValueRef union_value;3669 LLVMValueRef union_value;
3670 if (type_has_bits(enum_field->type_entry)) {3670 if (type_has_bits(enum_field->type_entry)) {
3671 uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,3671 uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
3672 union_type->type_ref);3672 union_type_ref);
3673 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,3673 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
3674 enum_field->type_entry->type_ref);3674 enum_field->type_entry->type_ref);
3675 uint64_t pad_bytes = union_type_bytes - field_type_bytes;3675 uint64_t pad_bytes = union_type_bytes - field_type_bytes;
...@@ -3685,7 +3685,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3685,7 +3685,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3685 union_value = LLVMConstStruct(fields, 2, false);3685 union_value = LLVMConstStruct(fields, 2, false);
3686 }3686 }
3687 } else {3687 } else {
3688 union_value = LLVMGetUndef(union_type->type_ref);3688 union_value = LLVMGetUndef(union_type_ref);
3689 }3689 }
3690 LLVMValueRef fields[] = {3690 LLVMValueRef fields[] = {
3691 tag_value,3691 tag_value,
test/cases/enum.zig+11
...@@ -120,3 +120,14 @@ const BareNumber = enum {...@@ -120,3 +120,14 @@ const BareNumber = enum {
120 Two,120 Two,
121 Three,121 Three,
122};122};
123
124
125test "enum alignment" {
126 comptime assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
127 comptime assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
128}
129
130const AlignTestEnum = enum {
131 A: [9]u8,
132 B: u64,
133};