| ... | ... | @@ -849,16 +849,43 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef |
| 849 | 849 | return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); |
| 850 | 850 | } |
| 851 | 851 | |
| 852 | | static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef target_ref, LLVMValueRef value, |
| 853 | | TypeTableEntry *child_type) |
| 852 | static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *ptr_type, |
| 853 | LLVMValueRef value) |
| 854 | 854 | { |
| 855 | TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type); |
| 856 | |
| 855 | 857 | if (!type_has_bits(child_type)) |
| 856 | 858 | return nullptr; |
| 857 | 859 | |
| 858 | 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, ""); |
| 860 | 886 | |
| 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 | 889 | return nullptr; |
| 863 | 890 | } |
| 864 | 891 | |
| ... | ... | @@ -903,7 +930,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 903 | 930 | LLVMBuildRet(g->builder, by_val_value); |
| 904 | 931 | } else { |
| 905 | 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 | 934 | LLVMBuildRetVoid(g->builder); |
| 908 | 935 | } |
| 909 | 936 | } else { |
| ... | ... | @@ -1549,7 +1576,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 1549 | 1576 | |
| 1550 | 1577 | if (have_init_expr) { |
| 1551 | 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 | 1581 | } else { |
| 1554 | 1582 | bool ignore_uninit = false; |
| 1555 | 1583 | // handle runtime stack allocation |
| ... | ... | @@ -1615,40 +1643,9 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 1615 | 1643 | |
| 1616 | 1644 | assert(instruction->ptr->value.type->id == TypeTableEntryIdPointer); |
| 1617 | 1645 | TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type); |
| 1618 | | TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type); |
| 1619 | 1646 | |
| 1620 | | if (!type_has_bits(child_type)) |
| 1621 | | return nullptr; |
| 1647 | gen_assign_raw(g, ptr, ptr_type, value); |
| 1622 | 1648 | |
| 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 | 1649 | return nullptr; |
| 1653 | 1650 | } |
| 1654 | 1651 | |
| ... | ... | @@ -2531,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I |
| 2531 | 2528 | |
| 2532 | 2529 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); |
| 2533 | 2530 | // 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 | 2532 | LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); |
| 2536 | 2533 | LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); |
| 2537 | 2534 | |
| ... | ... | @@ -2577,7 +2574,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa |
| 2577 | 2574 | LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr); |
| 2578 | 2575 | |
| 2579 | 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); |
| 2581 | 2578 | |
| 2582 | 2579 | return instruction->tmp_ptr; |
| 2583 | 2580 | } |
| ... | ... | @@ -2617,7 +2614,7 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir |
| 2617 | 2614 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, |
| 2618 | 2615 | LLVMPointerType(union_val_type->type_ref, 0), ""); |
| 2619 | 2616 | |
| 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 | } |
| 2622 | 2619 | |
| 2623 | 2620 | return tmp_struct_ptr; |
| ... | ... | @@ -2632,7 +2629,12 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 2632 | 2629 | |
| 2633 | 2630 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, ""); |
| 2634 | 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 | 2639 | return instruction->tmp_ptr; |
| 2638 | 2640 | } |
| ... | ... | @@ -2655,7 +2657,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 2655 | 2657 | LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false), |
| 2656 | 2658 | }; |
| 2657 | 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 | } |
| 2660 | 2662 | |
| 2661 | 2663 | return tmp_array_ptr; |