authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-06 15:04:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-06 15:04:18-04:00
log47f58d6d029cabb46064557f8e047970a2fa52fc
tree9d095d358c6d8bd8523b887482f1bc52974eac0e
parent10dbc735fe4e4575821837f00eb173286a1f88ee

fix runtime struct initialization of bitfield

closes #308

3 files changed, 68 insertions(+), 44 deletions(-)

doc/vim/syntax/zig.vim+1-1
...@@ -25,7 +25,7 @@ syn keyword zigBoolean true false...@@ -25,7 +25,7 @@ syn keyword zigBoolean true false
25syn match zigOperator display "\%(+%\?\|-%\?\|/\|*%\?\|=\|\^\|&\|?\||\|!\|>\|<\|%\|<<%\?\|>>\)=\?"25syn match zigOperator display "\%(+%\?\|-%\?\|/\|*%\?\|=\|\^\|&\|?\||\|!\|>\|<\|%\|<<%\?\|>>\)=\?"
26syn match zigArrowCharacter display "->"26syn match zigArrowCharacter display "->"
2727
28syn match zigDecNumber display "\<[0-9]*\%(.[0-9]\+\)\=\%([eE][+-]\?[0-9]\+\)\="28syn match zigDecNumber display "\<[0-9]\+\%(.[0-9]\+\)\=\%([eE][+-]\?[0-9]\+\)\="
29syn match zigHexNumber display "\<0x[a-fA-F0-9]\+\%(.[a-fA-F0-9]\+\%([pP][+-]\?[0-9]\+\)\?\)\="29syn match zigHexNumber display "\<0x[a-fA-F0-9]\+\%(.[a-fA-F0-9]\+\%([pP][+-]\?[0-9]\+\)\?\)\="
30syn match zigOctNumber display "\<0o[0-7]\+"30syn match zigOctNumber display "\<0o[0-7]\+"
31syn match zigBinNumber display "\<0b[01]\+\%(.[01]\+\%([eE][+-]\?[0-9]\+\)\?\)\="31syn match zigBinNumber display "\<0b[01]\+\%(.[01]\+\%([eE][+-]\?[0-9]\+\)\?\)\="
src/codegen.cpp+45-43
...@@ -849,16 +849,43 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef...@@ -849,16 +849,43 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
849 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");849 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
850}850}
851851
852static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef target_ref, LLVMValueRef value,852static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *ptr_type,
853 TypeTableEntry *child_type)853 LLVMValueRef value)
854{854{
855 TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type);
856
855 if (!type_has_bits(child_type))857 if (!type_has_bits(child_type))
856 return nullptr;858 return nullptr;
857859
858 if (handle_is_ptr(child_type))860 if (handle_is_ptr(child_type))
859 return gen_struct_memcpy(g, value, target_ref, child_type);861 return gen_struct_memcpy(g, value, ptr, child_type);
862
863 uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
864 if (unaligned_bit_count == 0) {
865 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
866 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
867 return nullptr;
868 }
869
870 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
871
872 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
873 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
874 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;
875 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
876
877 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
878 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
879 mask_val = LLVMConstShl(mask_val, shift_amt_val);
880 mask_val = LLVMConstNot(mask_val);
881
882 LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, "");
883 LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value, LLVMTypeOf(containing_int), "");
884 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
885 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
860886
861 LLVMBuildStore(g->builder, value, target_ref);887 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, ored_value, ptr);
888 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
862 return nullptr;889 return nullptr;
863}890}
864891
...@@ -903,7 +930,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -903,7 +930,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
903 LLVMBuildRet(g->builder, by_val_value);930 LLVMBuildRet(g->builder, by_val_value);
904 } else {931 } else {
905 assert(g->cur_ret_ptr);932 assert(g->cur_ret_ptr);
906 gen_assign_raw(g, g->cur_ret_ptr, value, return_type);933 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
907 LLVMBuildRetVoid(g->builder);934 LLVMBuildRetVoid(g->builder);
908 }935 }
909 } else {936 } else {
...@@ -1549,7 +1576,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,...@@ -1549,7 +1576,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
15491576
1550 if (have_init_expr) {1577 if (have_init_expr) {
1551 assert(var->value->type == init_value->value.type);1578 assert(var->value->type == init_value->value.type);
1552 gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->value->type);1579 gen_assign_raw(g, var->value_ref, get_pointer_to_type(g, var->value->type, false),
1580 ir_llvm_value(g, init_value));
1553 } else {1581 } else {
1554 bool ignore_uninit = false;1582 bool ignore_uninit = false;
1555 // handle runtime stack allocation1583 // handle runtime stack allocation
...@@ -1615,40 +1643,9 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir...@@ -1615,40 +1643,9 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
16151643
1616 assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer);1644 assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer);
1617 TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type);1645 TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type);
1618 TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type);
16191646
1620 if (!type_has_bits(child_type))1647 gen_assign_raw(g, ptr, ptr_type, value);
1621 return nullptr;
16221648
1623 if (handle_is_ptr(child_type))
1624 return gen_struct_memcpy(g, value, ptr, child_type);
1625
1626 uint32_t unaligned_bit_count = ptr_type->data.pointer.unaligned_bit_count;
1627 if (unaligned_bit_count == 0) {
1628 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
1629 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1630 return nullptr;
1631 }
1632
1633 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
1634
1635 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1636 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1637 uint32_t shift_amt = host_bit_count - bit_offset - unaligned_bit_count;
1638 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
1639
1640 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
1641 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
1642 mask_val = LLVMConstShl(mask_val, shift_amt_val);
1643 mask_val = LLVMConstNot(mask_val);
1644
1645 LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, "");
1646 LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value, LLVMTypeOf(containing_int), "");
1647 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
1648 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
1649
1650 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, ored_value, ptr);
1651 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1652 return nullptr;1649 return nullptr;
1653}1650}
16541651
...@@ -2531,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -2531,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
25312528
2532 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");2529 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
2533 // child_type and instruction->value->value.type may differ by constness2530 // child_type and instruction->value->value.type may differ by constness
2534 gen_assign_raw(g, val_ptr, payload_val, child_type);2531 gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
2535 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");2532 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
2536 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);2533 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
25372534
...@@ -2577,7 +2574,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa...@@ -2577,7 +2574,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
2577 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);2574 LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
25782575
2579 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");2576 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
2580 gen_assign_raw(g, payload_ptr, payload_val, child_type);2577 gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val);
25812578
2582 return instruction->tmp_ptr;2579 return instruction->tmp_ptr;
2583}2580}
...@@ -2617,7 +2614,7 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir...@@ -2617,7 +2614,7 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir
2617 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,2614 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
2618 LLVMPointerType(union_val_type->type_ref, 0), "");2615 LLVMPointerType(union_val_type->type_ref, 0), "");
26192616
2620 gen_assign_raw(g, bitcasted_union_field_ptr, new_union_val, union_val_type);2617 gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val);
2621 }2618 }
26222619
2623 return tmp_struct_ptr;2620 return tmp_struct_ptr;
...@@ -2632,7 +2629,12 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,...@@ -2632,7 +2629,12 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
26322629
2633 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, "");2630 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, "");
2634 LLVMValueRef value = ir_llvm_value(g, field->value);2631 LLVMValueRef value = ir_llvm_value(g, field->value);
2635 gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry);2632
2633 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
2634 false, false,
2635 type_struct_field->packed_bits_offset, type_struct_field->unaligned_bit_count);
2636
2637 gen_assign_raw(g, field_ptr, ptr_type, value);
2636 }2638 }
2637 return instruction->tmp_ptr;2639 return instruction->tmp_ptr;
2638}2640}
...@@ -2655,7 +2657,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -2655,7 +2657,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
2655 LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),2657 LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
2656 };2658 };
2657 LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");2659 LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
2658 gen_assign_raw(g, elem_ptr, elem_val, child_type);2660 gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val);
2659 }2661 }
26602662
2661 return tmp_array_ptr;2663 return tmp_array_ptr;
test/cases/struct.zig+22
...@@ -361,3 +361,25 @@ test "alignedArrayOfPackedStruct" {...@@ -361,3 +361,25 @@ test "alignedArrayOfPackedStruct" {
361 assert(ptr.a[1].a == 0xbb);361 assert(ptr.a[1].a == 0xbb);
362 assert(ptr.a[1].b == 0xbb);362 assert(ptr.a[1].b == 0xbb);
363}363}
364
365
366
367test "runtime struct initialization of bitfield" {
368 const s1 = Nibbles { .x = x1, .y = x1 };
369 const s2 = Nibbles { .x = u4(x2), .y = u4(x2) };
370
371 assert(s1.x == x1);
372 assert(s1.y == x1);
373 assert(s2.x == u4(x2));
374 assert(s2.y == u4(x2));
375}
376
377const u4 = @intType(false, 4);
378
379var x1 = u4(1);
380var x2 = u8(2);
381
382const Nibbles = packed struct {
383 x: u4,
384 y: u4,
385};