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
12381238 return nullptr;
12391239 }
12401240
1241 bool big_endian = g->is_big_endian;
1242
12411243 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
12421244
12431245 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
12441246 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;
12461248 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
12471249
12481250 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
......@@ -2198,12 +2200,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
21982200 if (unaligned_bit_count == 0)
21992201 return get_handle_value(g, ptr, child_type, ptr_type);
22002202
2203 bool big_endian = g->is_big_endian;
2204
22012205 assert(!handle_is_ptr(child_type));
22022206 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
22032207
22042208 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
22052209 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
22082212 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
22092213 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
37963800 case TypeTableEntryIdStruct:
37973801 {
37983802 assert(type_entry->data.structure.layout == ContainerLayoutPacked);
3803 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
37993804
38003805 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3806 size_t used_bits = 0;
38013807 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
38023808 TypeStructField *field = &type_entry->data.structure.fields[i];
38033809 if (field->gen_index == SIZE_MAX) {
38043810 continue;
38053811 }
38063812 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);
3808 val = LLVMConstShl(val, shift_amt);
3809 val = LLVMConstOr(val, child_val);
3813 if (is_big_endian) {
3814 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, field->packed_bits_size, false);
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 }
38103823 }
38113824 return val;
38123825 }
......@@ -3931,9 +3944,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
39313944 fields[type_struct_field->gen_index] = val;
39323945 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
39333946 } else {
3947 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
39343948 LLVMTypeRef big_int_type_ref = LLVMStructGetTypeAtIndex(type_entry->type_ref,
39353949 (unsigned)type_struct_field->gen_index);
39363950 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
3951 size_t used_bits = 0;
39373952 for (size_t i = src_field_index; i < src_field_index_end; i += 1) {
39383953 TypeStructField *it_field = &type_entry->data.structure.fields[i];
39393954 if (it_field->gen_index == SIZE_MAX) {
......@@ -3941,10 +3956,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
39413956 }
39423957 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref,
39433958 &const_val->data.x_struct.fields[i]);
3944 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
3945 it_field->packed_bits_size, false);
3946 val = LLVMConstShl(val, shift_amt);
3947 val = LLVMConstOr(val, child_val);
3959 if (is_big_endian) {
3960 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref,
3961 it_field->packed_bits_size, false);
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 }
39483970 }
39493971 fields[type_struct_field->gen_index] = val;
39503972 }
test/cases/struct.zig+25
......@@ -379,3 +379,28 @@ const Nibbles = packed struct {
379379 x: u4,
380380 y: u4,
381381};
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}