| ... | ... | @@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 88 | 88 | g->exported_symbol_names.init(8); |
| 89 | 89 | g->external_prototypes.init(8); |
| 90 | 90 | g->string_literals_table.init(16); |
| 91 | g->workaround_struct_gep_table.init(8); |
| 91 | 92 | g->is_test_build = false; |
| 92 | 93 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 93 | 94 | buf_resize(&g->global_asm, 0); |
| ... | ... | @@ -2781,6 +2782,52 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2781 | 2782 | } |
| 2782 | 2783 | } |
| 2783 | 2784 | |
| 2785 | static LLVMValueRef get_workaround_struct_gep_fn_val(CodeGen *g, LLVMTypeRef struct_ptr_type, uint32_t index) { |
| 2786 | WorkaroundStructGEPId hash_id = {struct_ptr_type, index}; |
| 2787 | auto existing_entry = g->workaround_struct_gep_table.maybe_get(hash_id); |
| 2788 | if (existing_entry) |
| 2789 | return existing_entry->value; |
| 2790 | |
| 2791 | LLVMTypeRef arg_types[] = { |
| 2792 | struct_ptr_type, |
| 2793 | }; |
| 2794 | LLVMTypeRef result_type = LLVMStructGetTypeAtIndex(LLVMGetElementType(struct_ptr_type), index); |
| 2795 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(result_type, 0), arg_types, 1, false); |
| 2796 | |
| 2797 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_workaround_llvm_struct_gep"), false); |
| 2798 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 2799 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 2800 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| 2801 | addLLVMFnAttr(fn_val, "nounwind"); |
| 2802 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); |
| 2803 | |
| 2804 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 2805 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| 2806 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| 2807 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 2808 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 2809 | |
| 2810 | LLVMValueRef result = LLVMBuildStructGEP(g->builder, LLVMGetParam(fn_val, 0), index, ""); |
| 2811 | LLVMBuildRet(g->builder, result); |
| 2812 | |
| 2813 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 2814 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 2815 | |
| 2816 | g->workaround_struct_gep_table.put(hash_id, fn_val); |
| 2817 | return fn_val; |
| 2818 | } |
| 2819 | |
| 2820 | static LLVMValueRef gen_workaround_struct_gep(CodeGen *g, LLVMValueRef struct_ptr, uint32_t field_index) { |
| 2821 | if (g->cur_workaround_gep_on) { |
| 2822 | // We need to generate a normal StructGEP but due to llvm bugs we have to workaround it by |
| 2823 | // putting the GEP in a function call |
| 2824 | LLVMValueRef fn_val = get_workaround_struct_gep_fn_val(g, LLVMTypeOf(struct_ptr), field_index); |
| 2825 | return LLVMBuildCall(g->builder, fn_val, &struct_ptr, 1, ""); |
| 2826 | } else { |
| 2827 | return LLVMBuildStructGEP(g->builder, struct_ptr, field_index, ""); |
| 2828 | } |
| 2829 | } |
| 2830 | |
| 2784 | 2831 | static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, |
| 2785 | 2832 | IrInstructionStructFieldPtr *instruction) |
| 2786 | 2833 | { |
| ... | ... | @@ -2799,7 +2846,7 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 2799 | 2846 | } |
| 2800 | 2847 | |
| 2801 | 2848 | assert(field->gen_index != SIZE_MAX); |
| 2802 | | return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); |
| 2849 | return gen_workaround_struct_gep(g, struct_ptr, field->gen_index); |
| 2803 | 2850 | } |
| 2804 | 2851 | |
| 2805 | 2852 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, |
| ... | ... | @@ -3655,7 +3702,7 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI |
| 3655 | 3702 | |
| 3656 | 3703 | LLVMValueRef err_val; |
| 3657 | 3704 | if (type_has_bits(payload_type)) { |
| 3658 | | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3705 | LLVMValueRef err_val_ptr = gen_workaround_struct_gep(g, err_union_handle, err_union_err_index); |
| 3659 | 3706 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3660 | 3707 | } else { |
| 3661 | 3708 | err_val = err_union_handle; |
| ... | ... | @@ -3674,7 +3721,12 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 3674 | 3721 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3675 | 3722 | |
| 3676 | 3723 | if (type_has_bits(payload_type)) { |
| 3677 | | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3724 | LLVMValueRef err_val_ptr; |
| 3725 | if (g->cur_workaround_gep_on) { |
| 3726 | err_val_ptr = gen_workaround_struct_gep(g, err_union_handle, err_union_err_index); |
| 3727 | } else { |
| 3728 | err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3729 | } |
| 3678 | 3730 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3679 | 3731 | } else { |
| 3680 | 3732 | return err_union_handle; |
| ... | ... | @@ -3696,7 +3748,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3696 | 3748 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { |
| 3697 | 3749 | LLVMValueRef err_val; |
| 3698 | 3750 | if (type_has_bits(payload_type)) { |
| 3699 | | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); |
| 3751 | LLVMValueRef err_val_ptr = gen_workaround_struct_gep(g, err_union_handle, err_union_err_index); |
| 3700 | 3752 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3701 | 3753 | } else { |
| 3702 | 3754 | err_val = err_union_handle; |
| ... | ... | @@ -3714,7 +3766,11 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3714 | 3766 | } |
| 3715 | 3767 | |
| 3716 | 3768 | if (type_has_bits(payload_type)) { |
| 3717 | | return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); |
| 3769 | if (g->cur_workaround_gep_on) { |
| 3770 | return gen_workaround_struct_gep(g, err_union_handle, err_union_payload_index); |
| 3771 | } else { |
| 3772 | return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); |
| 3773 | } |
| 3718 | 3774 | } else { |
| 3719 | 3775 | return nullptr; |
| 3720 | 3776 | } |
| ... | ... | @@ -3934,6 +3990,7 @@ static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, I |
| 3934 | 3990 | coro_id, |
| 3935 | 3991 | coro_mem_ptr, |
| 3936 | 3992 | }; |
| 3993 | g->cur_workaround_gep_on = false; |
| 3937 | 3994 | return LLVMBuildCall(g->builder, get_coro_begin_fn_val(g), params, 2, ""); |
| 3938 | 3995 | } |
| 3939 | 3996 | |
| ... | ... | @@ -5073,6 +5130,7 @@ static void do_code_gen(CodeGen *g) { |
| 5073 | 5130 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 5074 | 5131 | g->cur_fn = fn_table_entry; |
| 5075 | 5132 | g->cur_fn_val = fn; |
| 5133 | g->cur_workaround_gep_on = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 5076 | 5134 | TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 5077 | 5135 | if (handle_is_ptr(return_type)) { |
| 5078 | 5136 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |