Skip to content

Commit 95aed8c

Browse files
committed
Merge branch 'align'
2 parents e726925 + a0ae575 commit 95aed8c

File tree

4 files changed

+94
-50
lines changed

4 files changed

+94
-50
lines changed

src/all_types.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ struct TypeTableEntryEnum {
977977
TypeEnumField *fields;
978978
bool is_invalid; // true if any fields are invalid
979979
TypeTableEntry *tag_type;
980-
TypeTableEntry *union_type;
980+
LLVMTypeRef union_type_ref;
981981

982982
ScopeDecls *decls_scope;
983983

@@ -989,6 +989,9 @@ struct TypeTableEntryEnum {
989989

990990
bool zero_bits_loop_flag;
991991
bool zero_bits_known;
992+
993+
size_t gen_union_index;
994+
size_t gen_tag_index;
992995
};
993996

994997
struct TypeTableEntryEnumTag {
@@ -1633,7 +1636,7 @@ struct ScopeDecls {
16331636
struct ScopeBlock {
16341637
Scope base;
16351638

1636-
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
1639+
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
16371640
bool safety_off;
16381641
AstNode *safety_set_node;
16391642
bool fast_math_off;
@@ -2626,9 +2629,6 @@ static const size_t slice_len_index = 1;
26262629
static const size_t maybe_child_index = 0;
26272630
static const size_t maybe_null_index = 1;
26282631

2629-
static const size_t enum_gen_tag_index = 0;
2630-
static const size_t enum_gen_union_index = 1;
2631-
26322632
static const size_t err_union_err_index = 0;
26332633
static const size_t err_union_payload_index = 1;
26342634

src/analyze.cpp

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,9 +1245,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
12451245
uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;
12461246
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;
12491250
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

12521253
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
12531254
ImportTableEntry *import = get_scope_import(scope);
@@ -1271,27 +1272,28 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
12711272
if (!type_has_bits(field_type))
12721273
continue;
12731274

1274-
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);
1275+
uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
1276+
uint64_t preferred_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, field_type->type_ref);
12761277

1277-
assert(debug_size_in_bits > 0);
1278-
assert(debug_align_in_bits > 0);
1278+
assert(store_size_in_bits > 0);
1279+
assert(preferred_align_in_bits > 0);
12791280

12801281
union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
12811282
ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
12821283
import->di_file, (unsigned)(field_node->line + 1),
1283-
debug_size_in_bits,
1284-
debug_align_in_bits,
1284+
store_size_in_bits,
1285+
preferred_align_in_bits,
12851286
0,
12861287
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, store_size_in_bits);
12891290

1290-
if (!biggest_union_member ||
1291-
debug_size_in_bits > biggest_union_member_size_in_bits)
1291+
if (!most_aligned_union_member ||
1292+
preferred_align_in_bits > biggest_align_in_bits)
12921293
{
1293-
biggest_union_member = field_type;
1294-
biggest_union_member_size_in_bits = debug_size_in_bits;
1294+
most_aligned_union_member = field_type;
1295+
biggest_align_in_bits = preferred_align_in_bits;
1296+
size_of_most_aligned_member_in_bits = store_size_in_bits;
12951297
}
12961298
}
12971299

@@ -1300,27 +1302,52 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13001302
enum_type->data.enumeration.complete = true;
13011303

13021304
if (!enum_type->data.enumeration.is_invalid) {
1303-
enum_type->data.enumeration.union_type = biggest_union_member;
1304-
13051305
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
13061306
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
13071307
enum_type->data.enumeration.tag_type = tag_type_entry;
13081308

1309-
if (biggest_union_member) {
1309+
uint64_t align_of_tag_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1310+
1311+
if (most_aligned_union_member) {
13101312
// create llvm type for union
1311-
LLVMTypeRef union_element_type = biggest_union_member->type_ref;
1312-
LLVMTypeRef union_type_ref = LLVMStructType(&union_element_type, 1, false);
1313+
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1314+
LLVMTypeRef union_type_ref;
1315+
if (padding_in_bits > 0) {
1316+
TypeTableEntry *u8_type = get_int_type(g, false, 8);
1317+
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1318+
LLVMTypeRef union_element_types[] = {
1319+
most_aligned_union_member->type_ref,
1320+
padding_array->type_ref,
1321+
};
1322+
union_type_ref = LLVMStructType(union_element_types, 2, false);
1323+
} else {
1324+
LLVMTypeRef union_element_types[] = {
1325+
most_aligned_union_member->type_ref,
1326+
};
1327+
union_type_ref = LLVMStructType(union_element_types, 1, false);
1328+
}
1329+
enum_type->data.enumeration.union_type_ref = union_type_ref;
1330+
1331+
assert(8*LLVMPreferredAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1332+
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
1333+
1334+
if (align_of_tag_in_bits >= biggest_align_in_bits) {
1335+
enum_type->data.enumeration.gen_tag_index = 0;
1336+
enum_type->data.enumeration.gen_union_index = 1;
1337+
} else {
1338+
enum_type->data.enumeration.gen_union_index = 0;
1339+
enum_type->data.enumeration.gen_tag_index = 1;
1340+
}
13131341

13141342
// create llvm type for root struct
1315-
LLVMTypeRef root_struct_element_types[] = {
1316-
tag_type_entry->type_ref,
1317-
union_type_ref,
1318-
};
1343+
LLVMTypeRef root_struct_element_types[2];
1344+
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
1345+
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
13191346
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
13201347

13211348
// create debug type for tag
13221349
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1323-
uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1350+
uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
13241351
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
13251352
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
13261353
import->di_file, (unsigned)(decl_node->line + 1),
@@ -1331,11 +1358,12 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13311358
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
13321359
ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
13331360
import->di_file, (unsigned)(decl_node->line + 1),
1334-
biggest_union_member_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1361+
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
13351362
gen_field_count, 0, "");
13361363

13371364
// create debug types for members of root struct
1338-
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 0);
1365+
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1366+
enum_type->data.enumeration.gen_tag_index);
13391367
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
13401368
ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
13411369
import->di_file, (unsigned)(decl_node->line + 1),
@@ -1344,21 +1372,20 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13441372
tag_offset_in_bits,
13451373
0, tag_di_type);
13461374

1347-
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, 1);
1375+
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1376+
enum_type->data.enumeration.gen_union_index);
13481377
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
13491378
ZigLLVMTypeToScope(enum_type->di_type), "union_field",
13501379
import->di_file, (unsigned)(decl_node->line + 1),
1351-
biggest_union_member_size_in_bits,
1380+
biggest_size_in_bits,
13521381
biggest_align_in_bits,
13531382
union_offset_in_bits,
13541383
0, union_di_type);
13551384

13561385
// create debug type for root struct
1357-
ZigLLVMDIType *di_root_members[] = {
1358-
tag_member_di_type,
1359-
union_member_di_type,
1360-
};
1361-
1386+
ZigLLVMDIType *di_root_members[2];
1387+
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
1388+
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
13621389

13631390
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
13641391
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
@@ -1378,7 +1405,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13781405

13791406
// create debug type for tag
13801407
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1381-
uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1408+
uint64_t tag_debug_align_in_bits = 8*LLVMPreferredAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
13821409
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
13831410
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
13841411
import->di_file, (unsigned)(decl_node->line + 1),
@@ -2541,7 +2568,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
25412568
if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
25422569
return false;
25432570
}
2544-
if (!expected_type->data.fn.is_generic &&
2571+
if (!expected_type->data.fn.is_generic &&
25452572
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
25462573
!types_match_const_cast_only(
25472574
expected_type->data.fn.fn_type_id.return_type,

src/codegen.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,14 +2250,19 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
22502250
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
22512251
IrInstructionEnumFieldPtr *instruction)
22522252
{
2253+
TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type;
2254+
assert(enum_ptr_type->id == TypeTableEntryIdPointer);
2255+
TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type;
2256+
assert(enum_type->id == TypeTableEntryIdEnum);
2257+
22532258
TypeEnumField *field = instruction->field;
22542259

22552260
if (!type_has_bits(field->type_entry))
22562261
return nullptr;
22572262

22582263
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
22592264
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
2260-
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
2265+
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, "");
22612266
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
22622267

22632268
return bitcasted_union_field_ptr;
@@ -3112,7 +3117,7 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
31123117
if (enum_type->data.enumeration.gen_field_count == 0)
31133118
return enum_val;
31143119

3115-
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_gen_tag_index, "");
3120+
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
31163121
return get_handle_value(g, tag_field_ptr, tag_type, false);
31173122
}
31183123

@@ -3127,13 +3132,13 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
31273132

31283133
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
31293134

3130-
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_tag_index, "");
3135+
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, "");
31313136
LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
31323137

31333138
TypeTableEntry *union_val_type = instruction->field->type_entry;
31343139
if (type_has_bits(union_val_type)) {
31353140
LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
3136-
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_gen_union_index, "");
3141+
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, "");
31373142
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
31383143
LLVMPointerType(union_val_type->type_ref, 0), "");
31393144

@@ -3663,13 +3668,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
36633668
if (type_entry->data.enumeration.gen_field_count == 0) {
36643669
return tag_value;
36653670
} else {
3666-
TypeTableEntry *union_type = type_entry->data.enumeration.union_type;
3671+
LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
36673672
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
36683673
assert(enum_field->value == const_val->data.x_enum.tag);
36693674
LLVMValueRef union_value;
36703675
if (type_has_bits(enum_field->type_entry)) {
36713676
uint64_t union_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
3672-
union_type->type_ref);
3677+
union_type_ref);
36733678
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
36743679
enum_field->type_entry->type_ref);
36753680
uint64_t pad_bytes = union_type_bytes - field_type_bytes;
@@ -3685,12 +3690,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
36853690
union_value = LLVMConstStruct(fields, 2, false);
36863691
}
36873692
} else {
3688-
union_value = LLVMGetUndef(union_type->type_ref);
3693+
union_value = LLVMGetUndef(union_type_ref);
36893694
}
3690-
LLVMValueRef fields[] = {
3691-
tag_value,
3692-
union_value,
3693-
};
3695+
LLVMValueRef fields[2];
3696+
fields[type_entry->data.enumeration.gen_tag_index] = tag_value;
3697+
fields[type_entry->data.enumeration.gen_union_index] = union_value;
36943698
return LLVMConstStruct(fields, 2, false);
36953699
}
36963700
}

test/cases/enum.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,16 @@ const BareNumber = enum {
120120
Two,
121121
Three,
122122
};
123+
124+
125+
test "enum alignment" {
126+
comptime {
127+
assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf([9]u8));
128+
assert(@cAbiAlignOf(AlignTestEnum) >= @cAbiAlignOf(u64));
129+
}
130+
}
131+
132+
const AlignTestEnum = enum {
133+
A: [9]u8,
134+
B: u64,
135+
};

0 commit comments

Comments
 (0)