From 75ec7e4e0094af36375491d3201fbed559d4deae Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 20 Sep 2019 09:37:13 +0200 Subject: [PATCH 1/4] Fix generation of tail fields for packed struct --- src/analyze.cpp | 13 ++++++++++--- src/codegen.cpp | 32 +++++++++++++++++++++++++++----- test/stage1/behavior.zig | 2 +- test/stage1/behavior/struct.zig | 12 ++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 5e2a614ee9..5701ca9265 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7633,6 +7633,11 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa type->data.structure.resolve_status = ResolveStatusLLVMFull; } +static LLVMTypeRef get_llvm_array_type(unsigned byte_size) { + return byte_size == 1 ? + LLVMInt8Type() : LLVMArrayType(LLVMInt8Type(), byte_size); +} + static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status, ZigType *async_frame_type) { @@ -7730,9 +7735,8 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); if (full_abi_size * 8 == full_bit_count) { // next field recovers ABI alignment - element_types[gen_field_index] = LLVMIntType((unsigned)(full_bit_count)); + element_types[gen_field_index] = get_llvm_array_type(full_abi_size); gen_field_index += 1; - first_packed_bits_offset_misalign = SIZE_MAX; } } else if (get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) * 8 != field_size_in_bits) { @@ -7740,6 +7744,8 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS } else { // This is a byte-aligned field (both start and end) in a packed struct. element_types[gen_field_index] = get_llvm_type(g, field_type); + assert(get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) == + LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index])); gen_field_index += 1; } packed_bits_offset = next_packed_bits_offset; @@ -7802,11 +7808,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS if (first_packed_bits_offset_misalign != SIZE_MAX) { size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign; size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes); - element_types[gen_field_index] = LLVMIntType((unsigned)full_abi_size * 8); + element_types[gen_field_index] = get_llvm_array_type(full_abi_size); gen_field_index += 1; } if (type_has_bits(struct_type)) { + assert(struct_type->data.structure.gen_field_count == gen_field_index); LLVMStructSetBody(struct_type->llvm_type, element_types, (unsigned)struct_type->data.structure.gen_field_count, packed); } diff --git a/src/codegen.cpp b/src/codegen.cpp index aed45e74df..614b8381c5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1630,7 +1630,9 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, bool big_endian = g->is_big_endian; - LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); + LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); + LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); + LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, ""); uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); assert(host_bit_count == host_int_bytes * 8); uint32_t size_in_bits = type_size_bits(g, child_type); @@ -1654,7 +1656,7 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, ""); LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, ""); - gen_store(g, ored_value, ptr, ptr_type); + gen_store(g, ored_value, int_ptr, ptr_type); } static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { @@ -3375,7 +3377,10 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI bool big_endian = g->is_big_endian; - LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, ""); + LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0); + LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, ""); + LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, ""); + uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int)); assert(host_bit_count == host_int_bytes * 8); uint32_t size_in_bits = type_size_bits(g, child_type); @@ -6693,8 +6698,10 @@ check: switch (const_val->special) { make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val); } else { bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type - LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry), + LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry), (unsigned)type_struct_field->gen_index); + const size_t size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, field_ty); + LLVMTypeRef big_int_type_ref = LLVMIntType(size_in_bytes * 8); LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false); size_t used_bits = 0; for (size_t i = src_field_index; i < src_field_index_end; i += 1) { @@ -6717,7 +6724,22 @@ check: switch (const_val->special) { used_bits += packed_bits_size; } } - fields[type_struct_field->gen_index] = val; + if (LLVMGetTypeKind(field_ty) != LLVMArrayTypeKind) { + assert(LLVMGetTypeKind(field_ty) == LLVMIntegerTypeKind); + fields[type_struct_field->gen_index] = val; + } else { + const LLVMValueRef MASK = LLVMConstInt(LLVMInt8Type(), 255, false); + const LLVMValueRef AMT = LLVMConstInt(LLVMInt8Type(), 8, false); + + LLVMValueRef *values = allocate(size_in_bytes); + for (size_t i = 0; i < size_in_bytes; i++) { + const size_t idx = is_big_endian ? size_in_bytes - 1 - i : i; + values[idx] = LLVMConstTruncOrBitCast(LLVMConstAnd(val, MASK), LLVMInt8Type()); + val = LLVMConstLShr(val, AMT); + } + + fields[type_struct_field->gen_index] = LLVMConstArray(LLVMInt8Type(), values, size_in_bytes); + } } src_field_index = src_field_index_end; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 9b7f4305c2..d1f04b5157 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -106,5 +106,5 @@ comptime { _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); - _ = @import("behavior/widening.zig"); + // _ = @import("behavior/widening.zig"); } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 13d2dcc733..610e7328ec 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -658,3 +658,15 @@ test "struct field init with catch" { S.doTheTest(); comptime S.doTheTest(); } + +test "packed struct with non-ABI-aligned field" { + const S = packed struct { + x: u9, + y: u183, + }; + var s: S = undefined; + s.x = 1; + s.y = 42; + expect(s.x == 1); + expect(s.y == 42); +} From 093ffe9f161f604d7742afc0012c7c8f8437316d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 20 Sep 2019 16:39:18 +0200 Subject: [PATCH 2/4] Correct stack alignment for new stack --- src/codegen.cpp | 3 ++- src/zig_llvm.cpp | 4 ++++ src/zig_llvm.h | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 614b8381c5..951ca97a4b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3706,7 +3706,8 @@ static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) { LLVMValueRef ptr_addr = LLVMBuildPtrToInt(g->builder, ptr_value, LLVMTypeOf(len_value), ""); LLVMValueRef end_addr = LLVMBuildNUWAdd(g->builder, ptr_addr, len_value, ""); - LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), get_abi_alignment(g, g->builtin_types.entry_usize), false); + const unsigned alignment_factor = ZigLLVMDataLayoutGetStackAlignment(g->target_data_ref); + LLVMValueRef align_amt = LLVMConstInt(LLVMTypeOf(end_addr), alignment_factor, false); LLVMValueRef align_adj = LLVMBuildURem(g->builder, end_addr, align_amt, ""); return LLVMBuildNUWSub(g->builder, end_addr, align_adj, ""); } diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index c6f359f17d..8166173051 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -149,6 +149,10 @@ LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Tri return reinterpret_cast(TM); } +unsigned ZigLLVMDataLayoutGetStackAlignment(LLVMTargetDataRef TD) { + return unwrap(TD)->getStackAlignment(); +} + bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, bool is_small, bool time_report) diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 8f4d875cfe..8522a03c40 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -469,4 +469,6 @@ ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type, enum ZigLLVM_ObjectFormatType *oformat); +ZIG_EXTERN_C unsigned ZigLLVMDataLayoutGetStackAlignment(LLVMTargetDataRef TD); + #endif From 57f751a864613cc7c6b53774044d6f8742e05378 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 21 Sep 2019 11:20:41 +0200 Subject: [PATCH 3/4] Adjust tests for AArch64 --- test/stage1/behavior.zig | 6 ++++-- test/stage1/behavior/widening.zig | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index d1f04b5157..623feeb747 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -72,7 +72,9 @@ comptime { _ = @import("behavior/misc.zig"); _ = @import("behavior/muladd.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); - _ = @import("behavior/new_stack_call.zig"); + // See #3268 + if (@import("builtin").arch != .aarch64) + _ = @import("behavior/new_stack_call.zig"); _ = @import("behavior/null.zig"); _ = @import("behavior/optional.zig"); _ = @import("behavior/pointers.zig"); @@ -106,5 +108,5 @@ comptime { _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); - // _ = @import("behavior/widening.zig"); + _ = @import("behavior/widening.zig"); } diff --git a/test/stage1/behavior/widening.zig b/test/stage1/behavior/widening.zig index d79270b811..2bab106ada 100644 --- a/test/stage1/behavior/widening.zig +++ b/test/stage1/behavior/widening.zig @@ -23,5 +23,7 @@ test "float widening" { var b: f32 = a; var c: f64 = b; var d: f128 = c; - expect(d == a); + expect(a == b); + expect(b == c); + expect(c == d); } From 34d02f249b8c0742d5d575c439c38a3ed78f9583 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 21 Sep 2019 11:35:29 +0200 Subject: [PATCH 4/4] Fix a test on ARM due to the use of `undefined` ptr --- test/stage1/behavior/error.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index fefd95a850..983f790cbe 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -361,7 +361,8 @@ test "nested catch" { test "implicit cast to optional to error union to return result loc" { const S = struct { fn entry() void { - if (func(undefined)) |opt| { + var x: Foo = undefined; + if (func(&x)) |opt| { expect(opt != null); } else |_| @panic("expected non error"); }