authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-22 18:27:33-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-22 18:27:33-05:00
log760b307e8a8fcbb31fc1f2abb170ef7399aa917e
tree0e7ac5454744ea3f2929b1b1464ae2496577c69a
parente44a11341d21a14441c5607efa04b9c1be9baf5a

fix endianness of sub-byte integer fields in packed structs

closes #307

2 files changed, 56 insertions(+), 9 deletions(-)

src/codegen.cpp+31-9
...@@ -1238,11 +1238,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry...@@ -1238,11 +1238,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry
1238 return nullptr;1238 return nullptr;
1239 }1239 }
12401240
1241 bool big_endian = g->is_big_endian;
1242
1241 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");1243 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
12421244
1243 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;1245 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1244 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));1246 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1245 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;1247 uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
1246 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);1248 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
12471249
1248 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);1250 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
...@@ -2198,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -2198,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
2198 if (unaligned_bit_count == 0)2200 if (unaligned_bit_count == 0)
2199 return get_handle_value(g, ptr, child_type, ptr_type);2201 return get_handle_value(g, ptr, child_type, ptr_type);
22002202
2203 bool big_endian = g->is_big_endian;
2204
2201 assert(!handle_is_ptr(child_type));2205 assert(!handle_is_ptr(child_type));
2202 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");2206 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
22032207
2204 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;2208 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
2205 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));2209 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
2206 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;2210 uint32_t shift_amt = big_endian ? host_bit_count - bit_offset - unaligned_bit_count : bit_offset;
22072211
2208 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);2212 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
2209 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");2213 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
...@@ -3796,17 +3800,26 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -3796,17 +3800,26 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
3796 case TypeTableEntryIdStruct:3800 case TypeTableEntryIdStruct:
3797 {3801 {
3798 assert(type_entry->data.structure.layout == ContainerLayoutPacked);3802 assert(type_entry->data.structure.layout == ContainerLayoutPacked);
3803 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
37993804
3800 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);3805 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3806 size_t used_bits = 0;
3801 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {3807 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
3802 TypeStructField *field = &type_entry->data.structure.fields[i];3808 TypeStructField *field = &type_entry->data.structure.fields[i];
3803 if (field->gen_index == SIZE_MAX) {3809 if (field->gen_index == SIZE_MAX) {
3804 continue;3810 continue;
3805 }3811 }
3806 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]);3812 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, &const_val->data.x_struct.fields[i]);
3807 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);3813 if (is_big_endian) {
3808 val = LLVMConstShl(val, shift_amt);3814 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);
3809 val = LLVMConstOr(val, child_val);3815 val = LLVMConstShl(val, shift_amt);
3816 val = LLVMConstOr(val, child_val);
3817 } else {
3818 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
3819 LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
3820 val = LLVMConstOr(val, child_val_shifted);
3821 used_bits += field->packed_bits_size;
3822 }
3810 }3823 }
3811 return val;3824 return val;
3812 }3825 }
...@@ -3931,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3931,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3931 fields[type_struct_field->gen_index] = val;3944 fields[type_struct_field->gen_index] = val;
3932 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);3945 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
3933 } else {3946 } else {
3947 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
3934 LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,3948 LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,
3935 (unsigned)type_struct_field->gen_index);3949 (unsigned)type_struct_field->gen_index);
3936 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);3950 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3951 size_t used_bits = 0;
3937 for (size_t i = src_field_index; i < src_field_index_end; i += 1) {3952 for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
3938 TypeStructField *it_field = &type_entry->data.structure.fields[i];3953 TypeStructField *it_field = &type_entry->data.structure.fields[i];
3939 if (it_field->gen_index == SIZE_MAX) {3954 if (it_field->gen_index == SIZE_MAX) {
...@@ -3941,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3941,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3941 }3956 }
3942 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,3957 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,
3943 &const_val->data.x_struct.fields[i]);3958 &const_val->data.x_struct.fields[i]);
3944 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,3959 if (is_big_endian) {
3945 it_field->packed_bits_size, false);3960 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
3946 val = LLVMConstShl(val, shift_amt);3961 it_field->packed_bits_size, false);
3947 val = LLVMConstOr(val, child_val);3962 val = LLVMConstShl(val, shift_amt);
3963 val = LLVMConstOr(val, child_val);
3964 } else {
3965 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
3966 LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
3967 val = LLVMConstOr(val, child_val_shifted);
3968 used_bits += it_field->packed_bits_size;
3969 }
3948 }3970 }
3949 fields[type_struct_field->gen_index] = val;3971 fields[type_struct_field->gen_index] = val;
3950 }3972 }
test/cases/struct.zig+25
...@@ -379,3 +379,28 @@ const Nibbles = packed struct {...@@ -379,3 +379,28 @@ const Nibbles = packed struct {
379 x: u4,379 x: u4,
380 y: u4,380 y: u4,
381};381};
382
383const Bitfields = packed struct {
384 f1: u16,
385 f2: u16,
386 f3: u8,
387 f4: u8,
388 f5: u4,
389 f6: u4,
390 f7: u8,
391};
392
393test "native bit field understands endianness" {
394 var all: u64 = 0x7765443322221111;
395 var bytes: [8]u8 = undefined;
396 @memcpy(&bytes[0], @ptrCast(&u8, &all), 8);
397 var bitfields = *@ptrCast(&Bitfields, &bytes[0]);
398
399 assert(bitfields.f1 == 0x1111);
400 assert(bitfields.f2 == 0x2222);
401 assert(bitfields.f3 == 0x33);
402 assert(bitfields.f4 == 0x44);
403 assert(bitfields.f5 == 0x5);
404 assert(bitfields.f6 == 0x6);
405 assert(bitfields.f7 == 0x77);
406}