authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-09-20 09:37:13+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-09-21 11:39:43+02:00
log75ec7e4e0094af36375491d3201fbed559d4deae
tree97042414cbe0e4190aff5e80097c1270a61d500d
parent74d0b5bf7c5bdb5013cec7d6eb6b474fe1ad703a

Fix generation of tail fields for packed struct


4 files changed, 50 insertions(+), 9 deletions(-)

src/analyze.cpp+10-3
......@@ -7633,6 +7633,11 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
76337633 type->data.structure.resolve_status = ResolveStatusLLVMFull;
76347634}
76357635
7636static LLVMTypeRef get_llvm_array_type(unsigned byte_size) {
7637 return byte_size == 1 ?
7638 LLVMInt8Type() : LLVMArrayType(LLVMInt8Type(), byte_size);
7639}
7640
76367641static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status,
76377642 ZigType *async_frame_type)
76387643{
......@@ -7730,9 +7735,8 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
77307735 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
77317736 if (full_abi_size * 8 == full_bit_count) {
77327737 // next field recovers ABI alignment
7733 element_types[gen_field_index] = LLVMIntType((unsigned)(full_bit_count));
7738 element_types[gen_field_index] = get_llvm_array_type(full_abi_size);
77347739 gen_field_index += 1;
7735
77367740 first_packed_bits_offset_misalign = SIZE_MAX;
77377741 }
77387742 } 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
77407744 } else {
77417745 // This is a byte-aligned field (both start and end) in a packed struct.
77427746 element_types[gen_field_index] = get_llvm_type(g, field_type);
7747 assert(get_abi_size_bytes(field_type->size_in_bits, g->pointer_size_bytes) ==
7748 LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index]));
77437749 gen_field_index += 1;
77447750 }
77457751 packed_bits_offset = next_packed_bits_offset;
......@@ -7802,11 +7808,12 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
78027808 if (first_packed_bits_offset_misalign != SIZE_MAX) {
78037809 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
78047810 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
7805 element_types[gen_field_index] = LLVMIntType((unsigned)full_abi_size * 8);
7811 element_types[gen_field_index] = get_llvm_array_type(full_abi_size);
78067812 gen_field_index += 1;
78077813 }
78087814
78097815 if (type_has_bits(struct_type)) {
7816 assert(struct_type->data.structure.gen_field_count == gen_field_index);
78107817 LLVMStructSetBody(struct_type->llvm_type, element_types,
78117818 (unsigned)struct_type->data.structure.gen_field_count, packed);
78127819 }
src/codegen.cpp+27-5
......@@ -1630,7 +1630,9 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
16301630
16311631 bool big_endian = g->is_big_endian;
16321632
1633 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
1633 LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0);
1634 LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, "");
1635 LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, "");
16341636 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
16351637 assert(host_bit_count == host_int_bytes * 8);
16361638 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,
16541656 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
16551657 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
16561658
1657 gen_store(g, ored_value, ptr, ptr_type);
1659 gen_store(g, ored_value, int_ptr, ptr_type);
16581660}
16591661
16601662static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
......@@ -3375,7 +3377,10 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
33753377
33763378 bool big_endian = g->is_big_endian;
33773379
3378 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
3380 LLVMTypeRef int_ptr_ty = LLVMPointerType(LLVMIntType(host_int_bytes * 8), 0);
3381 LLVMValueRef int_ptr = LLVMBuildBitCast(g->builder, ptr, int_ptr_ty, "");
3382 LLVMValueRef containing_int = gen_load(g, int_ptr, ptr_type, "");
3383
33793384 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
33803385 assert(host_bit_count == host_int_bytes * 8);
33813386 uint32_t size_in_bits = type_size_bits(g, child_type);
......@@ -6693,8 +6698,10 @@ check: switch (const_val->special) {
66936698 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
66946699 } else {
66956700 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
6696 LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry),
6701 LLVMTypeRef field_ty = LLVMStructGetTypeAtIndex(get_llvm_type(g, type_entry),
66976702 (unsigned)type_struct_field->gen_index);
6703 const size_t size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, field_ty);
6704 LLVMTypeRef big_int_type_ref = LLVMIntType(size_in_bytes * 8);
66986705 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
66996706 size_t used_bits = 0;
67006707 for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
......@@ -6717,7 +6724,22 @@ check: switch (const_val->special) {
67176724 used_bits += packed_bits_size;
67186725 }
67196726 }
6720 fields[type_struct_field->gen_index] = val;
6727 if (LLVMGetTypeKind(field_ty) != LLVMArrayTypeKind) {
6728 assert(LLVMGetTypeKind(field_ty) == LLVMIntegerTypeKind);
6729 fields[type_struct_field->gen_index] = val;
6730 } else {
6731 const LLVMValueRef MASK = LLVMConstInt(LLVMInt8Type(), 255, false);
6732 const LLVMValueRef AMT = LLVMConstInt(LLVMInt8Type(), 8, false);
6733
6734 LLVMValueRef *values = allocate<LLVMValueRef>(size_in_bytes);
6735 for (size_t i = 0; i < size_in_bytes; i++) {
6736 const size_t idx = is_big_endian ? size_in_bytes - 1 - i : i;
6737 values[idx] = LLVMConstTruncOrBitCast(LLVMConstAnd(val, MASK), LLVMInt8Type());
6738 val = LLVMConstLShr(val, AMT);
6739 }
6740
6741 fields[type_struct_field->gen_index] = LLVMConstArray(LLVMInt8Type(), values, size_in_bytes);
6742 }
67216743 }
67226744
67236745 src_field_index = src_field_index_end;
test/stage1/behavior.zig+1-1
......@@ -106,5 +106,5 @@ comptime {
106106 _ = @import("behavior/vector.zig");
107107 _ = @import("behavior/void.zig");
108108 _ = @import("behavior/while.zig");
109 _ = @import("behavior/widening.zig");
109 // _ = @import("behavior/widening.zig");
110110}
test/stage1/behavior/struct.zig+12
......@@ -658,3 +658,15 @@ test "struct field init with catch" {
658658 S.doTheTest();
659659 comptime S.doTheTest();
660660}
661
662test "packed struct with non-ABI-aligned field" {
663 const S = packed struct {
664 x: u9,
665 y: u183,
666 };
667 var s: S = undefined;
668 s.x = 1;
669 s.y = 42;
670 expect(s.x == 1);
671 expect(s.y == 42);
672}