| ... | @@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out | ... | @@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 88 | g->exported_symbol_names.init(8); | 88 | g->exported_symbol_names.init(8); |
| 89 | g->external_prototypes.init(8); | 89 | g->external_prototypes.init(8); |
| 90 | g->string_literals_table.init(16); | 90 | g->string_literals_table.init(16); |
| | 91 | g->workaround_struct_gep_table.init(8); |
| 91 | g->is_test_build = false; | 92 | g->is_test_build = false; |
| 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); | 93 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 93 | buf_resize(&g->global_asm, 0); | 94 | buf_resize(&g->global_asm, 0); |
| ... | @@ -2781,6 +2782,52 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -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 | static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, | 2831 | static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, |
| 2785 | IrInstructionStructFieldPtr *instruction) | 2832 | IrInstructionStructFieldPtr *instruction) |
| 2786 | { | 2833 | { |
| ... | @@ -2799,7 +2846,7 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa | ... | @@ -2799,7 +2846,7 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 2799 | } | 2846 | } |
| 2800 | | 2847 | |
| 2801 | assert(field->gen_index != SIZE_MAX); | 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 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, | 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,7 +3702,7 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI |
| 3655 | | 3702 | |
| 3656 | LLVMValueRef err_val; | 3703 | LLVMValueRef err_val; |
| 3657 | if (type_has_bits(payload_type)) { | 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 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3706 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3660 | } else { | 3707 | } else { |
| 3661 | err_val = err_union_handle; | 3708 | err_val = err_union_handle; |
| ... | @@ -3674,7 +3721,12 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab | ... | @@ -3674,7 +3721,12 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 3674 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); | 3721 | LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); |
| 3675 | | 3722 | |
| 3676 | if (type_has_bits(payload_type)) { | 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 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3730 | return gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3679 | } else { | 3731 | } else { |
| 3680 | return err_union_handle; | 3732 | return err_union_handle; |
| ... | @@ -3696,7 +3748,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -3696,7 +3748,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3696 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { | 3748 | if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { |
| 3697 | LLVMValueRef err_val; | 3749 | LLVMValueRef err_val; |
| 3698 | if (type_has_bits(payload_type)) { | 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 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); | 3752 | err_val = gen_load_untyped(g, err_val_ptr, 0, false, ""); |
| 3701 | } else { | 3753 | } else { |
| 3702 | err_val = err_union_handle; | 3754 | err_val = err_union_handle; |
| ... | @@ -3714,7 +3766,11 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu | ... | @@ -3714,7 +3766,11 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3714 | } | 3766 | } |
| 3715 | | 3767 | |
| 3716 | if (type_has_bits(payload_type)) { | 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 | } else { | 3774 | } else { |
| 3719 | return nullptr; | 3775 | return nullptr; |
| 3720 | } | 3776 | } |
| ... | @@ -3934,6 +3990,7 @@ static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, I | ... | @@ -3934,6 +3990,7 @@ static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, I |
| 3934 | coro_id, | 3990 | coro_id, |
| 3935 | coro_mem_ptr, | 3991 | coro_mem_ptr, |
| 3936 | }; | 3992 | }; |
| | 3993 | g->cur_workaround_gep_on = false; |
| 3937 | return LLVMBuildCall(g->builder, get_coro_begin_fn_val(g), params, 2, ""); | 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,6 +5130,7 @@ static void do_code_gen(CodeGen *g) { |
| 5073 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); | 5130 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 5074 | g->cur_fn = fn_table_entry; | 5131 | g->cur_fn = fn_table_entry; |
| 5075 | g->cur_fn_val = fn; | 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 | TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; | 5134 | TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; |
| 5077 | if (handle_is_ptr(return_type)) { | 5135 | if (handle_is_ptr(return_type)) { |
| 5078 | g->cur_ret_ptr = LLVMGetParam(fn, 0); | 5136 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |