Skip to content

Commit 12ff91c

Browse files
committed
alignment of structs no longer depends on LLVM
fixes async function tests in optimized builds
1 parent 8a92899 commit 12ff91c

File tree

7 files changed

+204
-59
lines changed

7 files changed

+204
-59
lines changed

BRANCH_TODO

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* alignment of variables not being respected in async functions
12
* for loops need to spill the index. other payload captures probably also need to spill
23
* compile error (instead of crashing) for trying to get @Frame of generic function
34
* compile error (instead of crashing) for trying to async call and passing @Frame of wrong function

src/all_types.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,8 @@ struct ZigTypeOptional {
11481148
struct ZigTypeErrorUnion {
11491149
ZigType *err_set_type;
11501150
ZigType *payload_type;
1151+
size_t pad_bytes;
1152+
LLVMTypeRef pad_llvm_type;
11511153
};
11521154

11531155
struct ZigTypeErrorSet {
@@ -3564,6 +3566,7 @@ struct IrInstructionAllocaGen {
35643566

35653567
uint32_t align;
35663568
const char *name_hint;
3569+
size_t field_index;
35673570
};
35683571

35693572
struct IrInstructionEndExpr {

src/analyze.cpp

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
630630
size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);
631631
entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);
632632
entry->size_in_bits = entry->abi_size * 8;
633+
entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]);
633634
}
634635

635636
g->type_table.put(type_id, entry);
@@ -1499,7 +1500,7 @@ bool type_is_invalid(ZigType *type_entry) {
14991500
}
15001501

15011502

1502-
ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
1503+
static ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
15031504
ZigType *field_types[], size_t field_count, unsigned min_abi_align)
15041505
{
15051506
ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
@@ -1524,10 +1525,6 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15241525
if (field->type_entry->abi_align > abi_align) {
15251526
abi_align = field->type_entry->abi_align;
15261527
}
1527-
field->gen_index = struct_type->data.structure.gen_field_count;
1528-
struct_type->data.structure.gen_field_count += 1;
1529-
} else {
1530-
field->gen_index = SIZE_MAX;
15311528
}
15321529

15331530
auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
@@ -1537,14 +1534,16 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15371534
size_t next_offset = 0;
15381535
for (size_t i = 0; i < field_count; i += 1) {
15391536
TypeStructField *field = &struct_type->data.structure.fields[i];
1540-
if (field->gen_index == SIZE_MAX)
1537+
if (!type_has_bits(field->type_entry))
15411538
continue;
1539+
15421540
field->offset = next_offset;
1541+
1542+
// find the next non-zero-byte field for offset calculations
15431543
size_t next_src_field_index = i + 1;
15441544
for (; next_src_field_index < field_count; next_src_field_index += 1) {
1545-
if (struct_type->data.structure.fields[next_src_field_index].gen_index != SIZE_MAX) {
1545+
if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
15461546
break;
1547-
}
15481547
}
15491548
size_t next_abi_align = (next_src_field_index == field_count) ?
15501549
abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
@@ -5304,6 +5303,7 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
53045303

53055304
for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
53065305
IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
5306+
instruction->field_index = SIZE_MAX;
53075307
ZigType *ptr_type = instruction->base.value.type;
53085308
assert(ptr_type->id == ZigTypeIdPointer);
53095309
ZigType *child_type = ptr_type->data.pointer.child_type;
@@ -5327,6 +5327,7 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
53275327
} else {
53285328
name = buf_ptr(buf_sprintf("%s.%" ZIG_PRI_usize, instruction->name_hint, alloca_i));
53295329
}
5330+
instruction->field_index = field_types.length;
53305331
field_names.append(name);
53315332
field_types.append(child_type);
53325333
}
@@ -5949,6 +5950,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
59495950
entry->llvm_type = LLVMIntType(size_in_bits);
59505951
entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
59515952
entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
5953+
5954+
if (size_in_bits >= 128) {
5955+
// Override the incorrect alignment reported by LLVM. Clang does this as well.
5956+
// On x86_64 there are some instructions like CMPXCHG16B which require this.
5957+
// On all targets, integers 128 bits and above have ABI alignment of 16.
5958+
// See: https://github.com/ziglang/zig/issues/2987
5959+
assert(entry->abi_align == 8); // if this trips we can remove the workaround
5960+
entry->abi_align = 16;
5961+
}
59525962
}
59535963

59545964
const char u_or_i = is_signed ? 'i' : 'u';
@@ -6810,31 +6820,46 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
68106820
}
68116821

68126822
size_t field_count = struct_type->data.structure.src_field_count;
6813-
size_t gen_field_count = struct_type->data.structure.gen_field_count;
6814-
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
6823+
// Every field could potentially have a generated padding field after it.
6824+
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count * 2);
68156825

6816-
size_t gen_field_index = 0;
68176826
bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
68186827
size_t packed_bits_offset = 0;
68196828
size_t first_packed_bits_offset_misalign = SIZE_MAX;
68206829
size_t debug_field_count = 0;
68216830

68226831
// trigger all the recursive get_llvm_type calls
68236832
for (size_t i = 0; i < field_count; i += 1) {
6824-
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6825-
ZigType *field_type = type_struct_field->type_entry;
6833+
TypeStructField *field = &struct_type->data.structure.fields[i];
6834+
ZigType *field_type = field->type_entry;
68266835
if (!type_has_bits(field_type))
68276836
continue;
68286837
(void)get_llvm_type(g, field_type);
68296838
if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;
68306839
}
68316840

6832-
for (size_t i = 0; i < field_count; i += 1) {
6833-
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6834-
ZigType *field_type = type_struct_field->type_entry;
6841+
size_t gen_field_index = 0;
68356842

6843+
// Calculate what LLVM thinks the ABI align of the struct will be. We do this to avoid
6844+
// inserting padding bytes where LLVM would do it automatically.
6845+
size_t llvm_struct_abi_align = 0;
6846+
for (size_t i = 0; i < field_count; i += 1) {
6847+
ZigType *field_type = struct_type->data.structure.fields[i].type_entry;
68366848
if (!type_has_bits(field_type))
68376849
continue;
6850+
LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type);
6851+
size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type);
6852+
llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align);
6853+
}
6854+
6855+
for (size_t i = 0; i < field_count; i += 1) {
6856+
TypeStructField *field = &struct_type->data.structure.fields[i];
6857+
ZigType *field_type = field->type_entry;
6858+
6859+
if (!type_has_bits(field_type)) {
6860+
field->gen_index = SIZE_MAX;
6861+
continue;
6862+
}
68386863

68396864
if (packed) {
68406865
size_t field_size_in_bits = type_size_bits(g, field_type);
@@ -6871,11 +6896,44 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
68716896
llvm_type = get_llvm_type(g, field_type);
68726897
}
68736898
element_types[gen_field_index] = llvm_type;
6874-
6899+
field->gen_index = gen_field_index;
68756900
gen_field_index += 1;
6901+
6902+
// find the next non-zero-byte field for offset calculations
6903+
size_t next_src_field_index = i + 1;
6904+
for (; next_src_field_index < field_count; next_src_field_index += 1) {
6905+
if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
6906+
break;
6907+
}
6908+
size_t next_abi_align = (next_src_field_index == field_count) ?
6909+
struct_type->abi_align :
6910+
struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
6911+
size_t llvm_next_abi_align = (next_src_field_index == field_count) ?
6912+
llvm_struct_abi_align :
6913+
LLVMABIAlignmentOfType(g->target_data_ref,
6914+
get_llvm_type(g, struct_type->data.structure.fields[next_src_field_index].type_entry));
6915+
6916+
size_t next_offset = next_field_offset(field->offset, struct_type->abi_align,
6917+
field_type->abi_size, next_abi_align);
6918+
size_t llvm_next_offset = next_field_offset(field->offset, llvm_struct_abi_align,
6919+
LLVMABISizeOfType(g->target_data_ref, llvm_type), llvm_next_abi_align);
6920+
6921+
assert(next_offset >= llvm_next_offset);
6922+
if (next_offset > llvm_next_offset) {
6923+
size_t pad_bytes = next_offset - (field->offset + field_type->abi_size);
6924+
if (pad_bytes != 0) {
6925+
LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
6926+
element_types[gen_field_index] = pad_llvm_type;
6927+
gen_field_index += 1;
6928+
}
6929+
}
68766930
}
68776931
debug_field_count += 1;
68786932
}
6933+
if (!packed) {
6934+
struct_type->data.structure.gen_field_count = gen_field_index;
6935+
}
6936+
68796937
if (first_packed_bits_offset_misalign != SIZE_MAX) {
68806938
size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
68816939
size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
@@ -6884,19 +6942,20 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
68846942
}
68856943

68866944
if (type_has_bits(struct_type)) {
6887-
LLVMStructSetBody(struct_type->llvm_type, element_types, (unsigned)gen_field_count, packed);
6945+
LLVMStructSetBody(struct_type->llvm_type, element_types,
6946+
(unsigned)struct_type->data.structure.gen_field_count, packed);
68886947
}
68896948

68906949
ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
68916950
size_t debug_field_index = 0;
68926951
for (size_t i = 0; i < field_count; i += 1) {
6893-
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6894-
size_t gen_field_index = type_struct_field->gen_index;
6952+
TypeStructField *field = &struct_type->data.structure.fields[i];
6953+
size_t gen_field_index = field->gen_index;
68956954
if (gen_field_index == SIZE_MAX) {
68966955
continue;
68976956
}
68986957

6899-
ZigType *field_type = type_struct_field->type_entry;
6958+
ZigType *field_type = field->type_entry;
69006959

69016960
// if the field is a function, actually the debug info should be a pointer.
69026961
ZigLLVMDIType *field_di_type;
@@ -6914,13 +6973,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
69146973
uint64_t debug_align_in_bits;
69156974
uint64_t debug_offset_in_bits;
69166975
if (packed) {
6917-
debug_size_in_bits = type_struct_field->type_entry->size_in_bits;
6918-
debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;
6919-
debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;
6976+
debug_size_in_bits = field->type_entry->size_in_bits;
6977+
debug_align_in_bits = 8 * field->type_entry->abi_align;
6978+
debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host;
69206979
} else {
69216980
debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);
69226981
debug_align_in_bits = 8 * field_type->abi_align;
6923-
debug_offset_in_bits = 8 * type_struct_field->offset;
6982+
debug_offset_in_bits = 8 * field->offset;
69246983
}
69256984
unsigned line;
69266985
if (decl_node != nullptr) {
@@ -6930,7 +6989,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
69306989
line = 0;
69316990
}
69326991
di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
6933-
ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(type_struct_field->name),
6992+
ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(field->name),
69346993
di_file, line,
69356994
debug_size_in_bits,
69366995
debug_align_in_bits,
@@ -7171,7 +7230,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
71717230
union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
71727231
}
71737232

7174-
static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
7233+
static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
71757234
if (type->llvm_di_type != nullptr) return;
71767235

71777236
if (!type_has_bits(type)) {
@@ -7200,7 +7259,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
72007259
uint64_t debug_align_in_bits = 8*type->abi_align;
72017260
type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,
72027261
debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));
7203-
assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFull));
7262+
assertNoError(type_resolve(g, elem_type, wanted_resolve_status));
72047263
} else {
72057264
ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
72067265
LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);
@@ -7326,10 +7385,17 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
73267385
} else {
73277386
LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
73287387
LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
7329-
LLVMTypeRef elem_types[2];
7388+
LLVMTypeRef elem_types[3];
73307389
elem_types[err_union_err_index] = err_set_llvm_type;
73317390
elem_types[err_union_payload_index] = payload_llvm_type;
7391+
73327392
type->llvm_type = LLVMStructType(elem_types, 2, false);
7393+
if (LLVMABISizeOfType(g->target_data_ref, type->llvm_type) != type->abi_size) {
7394+
// we need to do our own padding
7395+
type->data.error_union.pad_llvm_type = LLVMArrayType(LLVMInt8Type(), type->data.error_union.pad_bytes);
7396+
elem_types[2] = type->data.error_union.pad_llvm_type;
7397+
type->llvm_type = LLVMStructType(elem_types, 3, false);
7398+
}
73337399

73347400
ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
73357401
ZigLLVMDIFile *di_file = nullptr;
@@ -7511,6 +7577,7 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
75117577
}
75127578

75137579
void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
7580+
Error err;
75147581
if (fn->raw_di_type != nullptr) return;
75157582

75167583
ZigType *fn_type = fn->type_entry;
@@ -7529,8 +7596,10 @@ void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
75297596

75307597
ZigType *frame_type = get_coro_frame_type(g, fn);
75317598
ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7532-
gen_param_types.append(get_llvm_type(g, ptr_type));
7533-
param_di_types.append(get_llvm_di_type(g, ptr_type));
7599+
if ((err = type_resolve(g, ptr_type, ResolveStatusLLVMFwdDecl)))
7600+
zig_unreachable();
7601+
gen_param_types.append(ptr_type->llvm_type);
7602+
param_di_types.append(ptr_type->llvm_di_type);
75347603

75357604
// this parameter is used to pass the result pointer when await completes
75367605
gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
@@ -7726,7 +7795,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
77267795
case ZigTypeIdUnion:
77277796
return resolve_llvm_types_union(g, type, wanted_resolve_status);
77287797
case ZigTypeIdPointer:
7729-
return resolve_llvm_types_pointer(g, type);
7798+
return resolve_llvm_types_pointer(g, type, wanted_resolve_status);
77307799
case ZigTypeIdInt:
77317800
return resolve_llvm_types_integer(g, type);
77327801
case ZigTypeIdOptional:

src/analyze.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
3838
ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
3939
ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
4040
ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
41-
ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
42-
ZigType *field_types[], size_t field_count, unsigned min_abi_align);
4341
ZigType *get_test_fn_type(CodeGen *g);
4442
ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
4543
bool handle_is_ptr(ZigType *type_entry);

0 commit comments

Comments
 (0)