Skip to content

Commit 760b307

Browse files
committed
fix endianness of sub-byte integer fields in packed structs
closes #307
1 parent e44a113 commit 760b307

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

src/codegen.cpp

+31-9
Original file line numberDiff line numberDiff line change
@@ -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,20 +3944,29 @@ 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) {
39403955
continue;
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
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,28 @@ const Nibbles = packed struct {
379379
x: u4,
380380
y: u4,
381381
};
382+
383+
const 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+
393+
test "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+
}

0 commit comments

Comments
 (0)