| ... | @@ -2026,18 +2026,159 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { | ... | @@ -2026,18 +2026,159 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2026 | } | 2026 | } |
| 2027 | } | 2027 | } |
| 2028 | | 2028 | |
| | 2029 | static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| | 2030 | if (g->merge_err_ret_traces_fn_val) |
| | 2031 | return g->merge_err_ret_traces_fn_val; |
| | 2032 | |
| | 2033 | assert(g->stack_trace_type != nullptr); |
| | 2034 | |
| | 2035 | LLVMTypeRef param_types[] = { |
| | 2036 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), |
| | 2037 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), |
| | 2038 | }; |
| | 2039 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); |
| | 2040 | |
| | 2041 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false); |
| | 2042 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| | 2043 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| | 2044 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| | 2045 | addLLVMFnAttr(fn_val, "nounwind"); |
| | 2046 | add_uwtable_attr(g, fn_val); |
| | 2047 | // Error return trace memory is in the stack, which is impossible to be at address 0 |
| | 2048 | // on any architecture. |
| | 2049 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); |
| | 2050 | addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); |
| | 2051 | addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); |
| | 2052 | // Error return trace memory is in the stack, which is impossible to be at address 0 |
| | 2053 | // on any architecture. |
| | 2054 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); |
| | 2055 | addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); |
| | 2056 | addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); |
| | 2057 | if (g->build_mode == BuildModeDebug) { |
| | 2058 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); |
| | 2059 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); |
| | 2060 | } |
| | 2061 | |
| | 2062 | // this is above the ZigLLVMClearCurrentDebugLocation |
| | 2063 | LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g); |
| | 2064 | |
| | 2065 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| | 2066 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| | 2067 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| | 2068 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| | 2069 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| | 2070 | |
| | 2071 | // var frame_index: usize = undefined; |
| | 2072 | // var frames_left: usize = undefined; |
| | 2073 | // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { |
| | 2074 | // frame_index = 0; |
| | 2075 | // frames_left = src_stack_trace.index; |
| | 2076 | // if (frames_left == 0) return; |
| | 2077 | // } else { |
| | 2078 | // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len; |
| | 2079 | // frames_left = src_stack_trace.instruction_addresses.len; |
| | 2080 | // } |
| | 2081 | // while (true) { |
| | 2082 | // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]); |
| | 2083 | // frames_left -= 1; |
| | 2084 | // if (frames_left == 0) return; |
| | 2085 | // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; |
| | 2086 | // } |
| | 2087 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); |
| | 2088 | |
| | 2089 | LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index"); |
| | 2090 | LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left"); |
| | 2091 | |
| | 2092 | LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0); |
| | 2093 | LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1); |
| | 2094 | |
| | 2095 | size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| | 2096 | size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| | 2097 | LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, |
| | 2098 | (unsigned)src_index_field_index, ""); |
| | 2099 | LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, |
| | 2100 | (unsigned)src_addresses_field_index, ""); |
| | 2101 | ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; |
| | 2102 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; |
| | 2103 | LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, ""); |
| | 2104 | size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index; |
| | 2105 | LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, ""); |
| | 2106 | LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, ""); |
| | 2107 | LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, ""); |
| | 2108 | LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, ""); |
| | 2109 | LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, ""); |
| | 2110 | LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap"); |
| | 2111 | LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap"); |
| | 2112 | LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop"); |
| | 2113 | LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block); |
| | 2114 | |
| | 2115 | LLVMPositionBuilderAtEnd(g->builder, no_wrap_block); |
| | 2116 | LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type); |
| | 2117 | LLVMBuildStore(g->builder, usize_zero, frame_index_ptr); |
| | 2118 | LLVMBuildStore(g->builder, src_index_val, frames_left_ptr); |
| | 2119 | LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, ""); |
| | 2120 | LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block); |
| | 2121 | |
| | 2122 | LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block); |
| | 2123 | LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false); |
| | 2124 | LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, ""); |
| | 2125 | LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, ""); |
| | 2126 | LLVMBuildStore(g->builder, mod_len, frame_index_ptr); |
| | 2127 | LLVMBuildStore(g->builder, src_len_val, frames_left_ptr); |
| | 2128 | LLVMBuildBr(g->builder, loop_block); |
| | 2129 | |
| | 2130 | LLVMPositionBuilderAtEnd(g->builder, loop_block); |
| | 2131 | LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); |
| | 2132 | LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, ""); |
| | 2133 | LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, ""); |
| | 2134 | LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; |
| | 2135 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); |
| | 2136 | LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, ""); |
| | 2137 | LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); |
| | 2138 | LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); |
| | 2139 | LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue"); |
| | 2140 | LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block); |
| | 2141 | |
| | 2142 | LLVMPositionBuilderAtEnd(g->builder, return_block); |
| | 2143 | LLVMBuildRetVoid(g->builder); |
| | 2144 | |
| | 2145 | LLVMPositionBuilderAtEnd(g->builder, continue_block); |
| | 2146 | LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr); |
| | 2147 | LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, ""); |
| | 2148 | LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, ""); |
| | 2149 | LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, ""); |
| | 2150 | LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr); |
| | 2151 | LLVMBuildBr(g->builder, loop_block); |
| | 2152 | |
| | 2153 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| | 2154 | if (!g->strip_debug_symbols) { |
| | 2155 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| | 2156 | } |
| | 2157 | |
| | 2158 | g->merge_err_ret_traces_fn_val = fn_val; |
| | 2159 | return fn_val; |
| | 2160 | |
| | 2161 | } |
| 2029 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, | 2162 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, |
| 2030 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) | 2163 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) |
| 2031 | { | 2164 | { |
| 2032 | assert(g->have_err_ret_tracing); | 2165 | assert(g->have_err_ret_tracing); |
| 2033 | | 2166 | |
| 2034 | LLVMValueRef return_err_fn = get_return_err_fn(g); | 2167 | LLVMValueRef return_err_fn = get_return_err_fn(g); |
| 2035 | LLVMValueRef args[] = { | 2168 | LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope); |
| 2036 | get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope), | 2169 | ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1, |
| 2037 | }; | | |
| 2038 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | | |
| 2039 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | 2170 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| 2040 | return call_instruction; | 2171 | |
| | 2172 | if (fn_is_async(g->cur_fn) && g->cur_fn->calls_or_awaits_errorable_fn && |
| | 2173 | codegen_fn_has_err_ret_tracing_arg(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) |
| | 2174 | { |
| | 2175 | LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, g->cur_err_ret_trace_val_arg, ""); |
| | 2176 | LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; |
| | 2177 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, |
| | 2178 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| | 2179 | } |
| | 2180 | |
| | 2181 | return nullptr; |
| 2041 | } | 2182 | } |
| 2042 | | 2183 | |
| 2043 | static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id, | 2184 | static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id, |