authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-22 00:49:10-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-22 00:49:10-05:00
logd794549985fc9a3fd6d6b1620be15d290f6a759f
tree82e39db15fd95ecb7041ec7fea74857689d07982
parentcf5108f222107ed242d2dc2c37d76758157da542

bitfields support for array of non-store-aligned packed structs


6 files changed, 146 insertions(+), 57 deletions(-)

src/analyze.cpp+30-36
......@@ -163,6 +163,7 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so
163163}
164164
165165
166// TODO no reason to limit to 8/16/32/64
166167static size_t bits_needed_for_unsigned(uint64_t x) {
167168 if (x <= UINT8_MAX) {
168169 return 8;
......@@ -262,6 +263,14 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
262263 if (canon_type->id == TypeTableEntryIdStruct && canon_type->data.structure.layout == ContainerLayoutPacked) {
263264 uint64_t size_in_bits = type_size_bits(g, type_entry);
264265 return (size_in_bits + 7) / 8;
266 } else if (canon_type->id == TypeTableEntryIdArray) {
267 TypeTableEntry *canon_child_type = get_underlying_type(canon_type->data.array.child_type);
268 if (canon_child_type->id == TypeTableEntryIdStruct &&
269 canon_child_type->data.structure.layout == ContainerLayoutPacked)
270 {
271 uint64_t size_in_bits = type_size_bits(g, type_entry);
272 return (size_in_bits + 7) / 8;
273 }
265274 }
266275
267276 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
......@@ -280,6 +289,13 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
280289 result += type_size_bits(g, canon_type->data.structure.fields[i].type_entry);
281290 }
282291 return result;
292 } else if (canon_type->id == TypeTableEntryIdArray) {
293 TypeTableEntry *canon_child_type = get_underlying_type(canon_type->data.array.child_type);
294 if (canon_child_type->id == TypeTableEntryIdStruct &&
295 canon_child_type->data.structure.layout == ContainerLayoutPacked)
296 {
297 return canon_type->data.array.len * type_size_bits(g, canon_child_type);
298 }
283299 }
284300
285301 return LLVMSizeOfTypeInBits(g->target_data_ref, canon_type->type_ref);
......@@ -537,14 +553,6 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
537553
538554 ensure_complete_type(g, child_type);
539555
540 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
541 if (canon_child_type->id == TypeTableEntryIdStruct &&
542 canon_child_type->data.structure.layout == ContainerLayoutPacked &&
543 type_size_bits(g, canon_child_type) != 8 * type_size(g, canon_child_type))
544 {
545 zig_panic("TODO array of packed struct with unaligned size");
546 }
547
548556 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
549557 entry->zero_bits = (array_size == 0) || child_type->zero_bits;
550558
......@@ -1459,15 +1467,16 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
14591467 type_struct_field->packed_bits_offset = packed_bits_offset - first_packed_bits_offset_misalign;
14601468 type_struct_field->unaligned_bit_count = field_size_in_bits;
14611469
1462 if (next_packed_bits_offset % 8 == 0) {
1463 // next field recovers byte alignment
1464 size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
1465 element_types[gen_field_index] = LLVMIntType(full_bit_count);
1470 size_t full_bit_count = next_packed_bits_offset - first_packed_bits_offset_misalign;
1471 LLVMTypeRef int_type_ref = LLVMIntType(full_bit_count);
1472 if (8 * LLVMStoreSizeOfType(g->target_data_ref, int_type_ref) == full_bit_count) {
1473 // next field recovers store alignment
1474 element_types[gen_field_index] = int_type_ref;
14661475 gen_field_index += 1;
14671476
14681477 first_packed_bits_offset_misalign = SIZE_MAX;
14691478 }
1470 } else if (next_packed_bits_offset % 8 != 0) {
1479 } else if (8 * LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref) != field_size_in_bits) {
14711480 first_packed_bits_offset_misalign = packed_bits_offset;
14721481 type_struct_field->packed_bits_offset = 0;
14731482 type_struct_field->unaligned_bit_count = field_size_in_bits;
......@@ -1489,7 +1498,9 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
14891498 }
14901499 if (first_packed_bits_offset_misalign != SIZE_MAX) {
14911500 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
1492 element_types[gen_field_index] = LLVMIntType(full_bit_count);
1501 LLVMTypeRef int_type_ref = LLVMIntType(full_bit_count);
1502 size_t store_bit_count = 8 * LLVMStoreSizeOfType(g->target_data_ref, int_type_ref);
1503 element_types[gen_field_index] = LLVMIntType(store_bit_count);
14931504 gen_field_index += 1;
14941505 }
14951506
......@@ -3620,33 +3631,22 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
36203631 zig_unreachable();
36213632}
36223633
3623static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
3634uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
36243635 assert(type_entry->id == TypeTableEntryIdInt);
36253636 if (type_entry->data.integral.bit_count == 64) {
36263637 return UINT64_MAX;
3627 } else if (type_entry->data.integral.bit_count == 32) {
3628 return UINT32_MAX;
3629 } else if (type_entry->data.integral.bit_count == 16) {
3630 return UINT16_MAX;
3631 } else if (type_entry->data.integral.bit_count == 8) {
3632 return UINT8_MAX;
36333638 } else {
3634 zig_unreachable();
3639 return (((uint64_t)1) << type_entry->data.integral.bit_count) - 1;
36353640 }
36363641}
36373642
36383643static int64_t max_signed_val(TypeTableEntry *type_entry) {
36393644 assert(type_entry->id == TypeTableEntryIdInt);
3645
36403646 if (type_entry->data.integral.bit_count == 64) {
36413647 return INT64_MAX;
3642 } else if (type_entry->data.integral.bit_count == 32) {
3643 return INT32_MAX;
3644 } else if (type_entry->data.integral.bit_count == 16) {
3645 return INT16_MAX;
3646 } else if (type_entry->data.integral.bit_count == 8) {
3647 return INT8_MAX;
36483648 } else {
3649 zig_unreachable();
3649 return (((uint64_t)1) << (type_entry->data.integral.bit_count - 1)) - 1;
36503650 }
36513651}
36523652
......@@ -3654,14 +3654,8 @@ int64_t min_signed_val(TypeTableEntry *type_entry) {
36543654 assert(type_entry->id == TypeTableEntryIdInt);
36553655 if (type_entry->data.integral.bit_count == 64) {
36563656 return INT64_MIN;
3657 } else if (type_entry->data.integral.bit_count == 32) {
3658 return INT32_MIN;
3659 } else if (type_entry->data.integral.bit_count == 16) {
3660 return INT16_MIN;
3661 } else if (type_entry->data.integral.bit_count == 8) {
3662 return INT8_MIN;
36633657 } else {
3664 zig_unreachable();
3658 return -((int64_t)(((uint64_t)1) << (type_entry->data.integral.bit_count - 1)));
36653659 }
36663660}
36673661
src/analyze.hpp+1
......@@ -84,6 +84,7 @@ bool ir_get_var_is_comptime(VariableTableEntry *var);
8484bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
8585void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
8686int64_t min_signed_val(TypeTableEntry *type_entry);
87uint64_t max_unsigned_val(TypeTableEntry *type_entry);
8788
8889void render_const_value(Buf *buf, ConstExprValue *const_val);
8990void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);
src/codegen.cpp+29
......@@ -1466,6 +1466,27 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
14661466 array_type->data.array.len, false);
14671467 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
14681468 }
1469 if (array_ptr_type->data.pointer.unaligned_bit_count != 0) {
1470 return array_ptr_ptr;
1471 }
1472 TypeTableEntry *canon_child_type = get_underlying_type(array_type->data.array.child_type);
1473 if (canon_child_type->id == TypeTableEntryIdStruct &&
1474 canon_child_type->data.structure.layout == ContainerLayoutPacked)
1475 {
1476 LLVMTypeRef ptr_u8_type_ref = LLVMPointerType(LLVMInt8Type(), 0);
1477 LLVMValueRef u8_array_ptr = LLVMBuildBitCast(g->builder, array_ptr, ptr_u8_type_ref, "");
1478 size_t unaligned_bit_count = instruction->base.value.type->data.pointer.unaligned_bit_count;
1479 assert(unaligned_bit_count != 0);
1480 assert(unaligned_bit_count % 8 == 0);
1481 LLVMValueRef elem_size_bytes = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
1482 unaligned_bit_count / 8, false);
1483 LLVMValueRef byte_offset = LLVMBuildNUWMul(g->builder, subscript_value, elem_size_bytes, "");
1484 LLVMValueRef indices[] = {
1485 byte_offset
1486 };
1487 LLVMValueRef elem_byte_ptr = LLVMBuildInBoundsGEP(g->builder, u8_array_ptr, indices, 1, "");
1488 return LLVMBuildBitCast(g->builder, elem_byte_ptr, LLVMPointerType(canon_child_type->type_ref, 0), "");
1489 }
14691490 LLVMValueRef indices[] = {
14701491 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
14711492 subscript_value
......@@ -1552,11 +1573,19 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
15521573 IrInstructionStructFieldPtr *instruction)
15531574{
15541575 LLVMValueRef struct_ptr = ir_llvm_value(g, instruction->struct_ptr);
1576 // not necessarily a pointer. could be TypeTableEntryIdStruct
1577 TypeTableEntry *struct_ptr_type = instruction->struct_ptr->value.type;
15551578 TypeStructField *field = instruction->field;
15561579
15571580 if (!type_has_bits(field->type_entry))
15581581 return nullptr;
15591582
1583 if (struct_ptr_type->id == TypeTableEntryIdPointer &&
1584 struct_ptr_type->data.pointer.unaligned_bit_count != 0)
1585 {
1586 return struct_ptr;
1587 }
1588
15601589 assert(field->gen_index != SIZE_MAX);
15611590 return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");
15621591}
src/ir.cpp+21-19
......@@ -7412,21 +7412,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
74127412 return ira->codegen->builtin_types.entry_bool;
74137413}
74147414
7415static uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
7416 assert(type_entry->id == TypeTableEntryIdInt);
7417 if (type_entry->data.integral.bit_count == 64) {
7418 return UINT64_MAX;
7419 } else if (type_entry->data.integral.bit_count == 32) {
7420 return UINT32_MAX;
7421 } else if (type_entry->data.integral.bit_count == 16) {
7422 return UINT16_MAX;
7423 } else if (type_entry->data.integral.bit_count == 8) {
7424 return UINT8_MAX;
7425 } else {
7426 zig_unreachable();
7427 }
7428}
7429
74307415static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
74317416 ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
74327417 TypeTableEntry *type, bool wrapping_op)
......@@ -8844,8 +8829,21 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
88448829 buf_sprintf("index 0 outside array of size 0"));
88458830 }
88468831 TypeTableEntry *child_type = array_type->data.array.child_type;
8847 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
8848 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
8832 if (ptr_type->data.pointer.unaligned_bit_count == 0) {
8833 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
8834 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, 0, 0);
8835 } else {
8836 ConstExprValue *elem_val = ir_resolve_const(ira, elem_index, UndefBad);
8837 if (!elem_val)
8838 return ira->codegen->builtin_types.entry_invalid;
8839
8840 size_t bit_width = type_size_bits(ira->codegen, child_type);
8841 size_t bit_offset = bit_width * elem_val->data.x_bignum.data.x_uint;
8842
8843 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
8844 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
8845 bit_offset, bit_width);
8846 }
88498847 } else if (array_type->id == TypeTableEntryIdPointer) {
88508848 return_type = array_type;
88518849 } else if (is_slice(array_type)) {
......@@ -9072,9 +9070,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
90729070 return ptr_type;
90739071 }
90749072 }
9073 size_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset;
9074 size_t ptr_unaligned_bit_count = container_ptr->value.type->data.pointer.unaligned_bit_count;
9075 size_t unaligned_bit_count_for_result_type = (ptr_unaligned_bit_count == 0) ?
9076 field->unaligned_bit_count : type_size_bits(ira->codegen, field->type_entry);
90759077 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
9076 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const,
9077 is_volatile, field->packed_bits_offset, field->unaligned_bit_count);
9078 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
9079 ptr_bit_offset + field->packed_bits_offset, unaligned_bit_count_for_result_type);
90789080 } else {
90799081 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
90809082 field_ptr_instruction, container_ptr, container_type);
test/cases/misc.zig+12
......@@ -50,27 +50,39 @@ fn intTypeBuiltin() {
5050 assert(!usize.is_signed);
5151}
5252
53const u1 = @intType(false, 1);
54const u63 = @intType(false, 63);
55const i1 = @intType(true, 1);
56const i63 = @intType(true, 63);
57
5358fn minValueAndMaxValue() {
5459 @setFnTest(this);
5560
61 assert(@maxValue(u1) == 1);
5662 assert(@maxValue(u8) == 255);
5763 assert(@maxValue(u16) == 65535);
5864 assert(@maxValue(u32) == 4294967295);
5965 assert(@maxValue(u64) == 18446744073709551615);
6066
67 assert(@maxValue(i1) == 0);
6168 assert(@maxValue(i8) == 127);
6269 assert(@maxValue(i16) == 32767);
6370 assert(@maxValue(i32) == 2147483647);
71 assert(@maxValue(i63) == 4611686018427387903);
6472 assert(@maxValue(i64) == 9223372036854775807);
6573
74 assert(@minValue(u1) == 0);
6675 assert(@minValue(u8) == 0);
6776 assert(@minValue(u16) == 0);
6877 assert(@minValue(u32) == 0);
78 assert(@minValue(u63) == 0);
6979 assert(@minValue(u64) == 0);
7080
81 assert(@minValue(i1) == -1);
7182 assert(@minValue(i8) == -128);
7283 assert(@minValue(i16) == -32768);
7384 assert(@minValue(i32) == -2147483648);
85 assert(@minValue(i63) == -4611686018427387904);
7486 assert(@minValue(i64) == -9223372036854775808);
7587}
7688
test/cases/struct.zig+53-2
......@@ -285,8 +285,10 @@ const Foo96Bits = packed struct {
285285fn packedStruct24Bits() {
286286 @setFnTest(this);
287287
288 comptime assert(@sizeOf(Foo24Bits) == 3);
289 comptime assert(@sizeOf(Foo96Bits) == 12);
288 comptime {
289 assert(@sizeOf(Foo24Bits) == 3);
290 assert(@sizeOf(Foo96Bits) == 12);
291 }
290292
291293 var value = Foo96Bits {
292294 .a = 0,
......@@ -318,3 +320,52 @@ fn packedStruct24Bits() {
318320 assert(value.c == 1);
319321 assert(value.d == 1);
320322}
323
324const FooArray24Bits = packed struct {
325 a: u16,
326 b: [2]Foo24Bits,
327 c: u16,
328};
329
330fn packedArray24Bits() {
331 @setFnTest(this);
332
333 comptime {
334 assert(@sizeOf([9]Foo24Bits) == 9 * 3);
335 assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
336 }
337
338 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
339 bytes[bytes.len - 1] = 0xaa;
340 const ptr = &([]FooArray24Bits)(bytes[0...bytes.len - 1])[0];
341 assert(ptr.a == 0);
342 assert(ptr.b[0].field == 0);
343 assert(ptr.b[1].field == 0);
344 assert(ptr.c == 0);
345
346 ptr.a = @maxValue(u16);
347 assert(ptr.a == @maxValue(u16));
348 assert(ptr.b[0].field == 0);
349 assert(ptr.b[1].field == 0);
350 assert(ptr.c == 0);
351
352 ptr.b[0].field = @maxValue(u24);
353 assert(ptr.a == @maxValue(u16));
354 assert(ptr.b[0].field == @maxValue(u24));
355 assert(ptr.b[1].field == 0);
356 assert(ptr.c == 0);
357
358 ptr.b[1].field = @maxValue(u24);
359 assert(ptr.a == @maxValue(u16));
360 assert(ptr.b[0].field == @maxValue(u24));
361 assert(ptr.b[1].field == @maxValue(u24));
362 assert(ptr.c == 0);
363
364 ptr.c = @maxValue(u16);
365 assert(ptr.a == @maxValue(u16));
366 assert(ptr.b[0].field == @maxValue(u24));
367 assert(ptr.b[1].field == @maxValue(u24));
368 assert(ptr.c == @maxValue(u16));
369
370 assert(bytes[bytes.len - 1] == 0xaa);
371}