| ... | @@ -892,7 +892,8 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace | ... | @@ -892,7 +892,8 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace |
| 892 | msg_arg, | 892 | msg_arg, |
| 893 | stack_trace_arg, | 893 | stack_trace_arg, |
| 894 | }; | 894 | }; |
| 895 | ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, ""); | 895 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, ""); |
| | 896 | LLVMSetTailCall(call_instruction, true); |
| 896 | LLVMBuildUnreachable(g->builder); | 897 | LLVMBuildUnreachable(g->builder); |
| 897 | } | 898 | } |
| 898 | | 899 | |
| ... | @@ -919,6 +920,79 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { | ... | @@ -919,6 +920,79 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { |
| 919 | return g->memcpy_fn_val; | 920 | return g->memcpy_fn_val; |
| 920 | } | 921 | } |
| 921 | | 922 | |
| | 923 | static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| | 924 | if (g->return_err_fn != nullptr) |
| | 925 | return g->return_err_fn; |
| | 926 | |
| | 927 | assert(g->err_tag_type != nullptr); |
| | 928 | |
| | 929 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); |
| | 930 | |
| | 931 | LLVMTypeRef arg_types[] = { |
| | 932 | // error return trace pointer |
| | 933 | get_ptr_to_stack_trace_type(g)->type_ref, |
| | 934 | // return address |
| | 935 | ptr_u8, |
| | 936 | }; |
| | 937 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); |
| | 938 | |
| | 939 | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false); |
| | 940 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| | 941 | addLLVMFnAttr(fn_val, "cold"); |
| | 942 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| | 943 | LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); |
| | 944 | addLLVMFnAttr(fn_val, "nounwind"); |
| | 945 | add_uwtable_attr(g, fn_val); |
| | 946 | addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); |
| | 947 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); |
| | 948 | if (g->build_mode == BuildModeDebug) { |
| | 949 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); |
| | 950 | ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); |
| | 951 | } |
| | 952 | |
| | 953 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| | 954 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| | 955 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| | 956 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| | 957 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| | 958 | |
| | 959 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref; |
| | 960 | |
| | 961 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = return_address; |
| | 962 | |
| | 963 | LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0); |
| | 964 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| | 965 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, ""); |
| | 966 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| | 967 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)addresses_field_index, ""); |
| | 968 | |
| | 969 | LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, ""); |
| | 970 | LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), ""); |
| | 971 | LLVMValueRef address_indices[] = { |
| | 972 | LLVMConstNull(usize_type_ref), |
| | 973 | modded_val, |
| | 974 | }; |
| | 975 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, ""); |
| | 976 | |
| | 977 | LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, ""); |
| | 978 | |
| | 979 | LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, ""); |
| | 980 | gen_store_untyped(g, address_value, address_slot, 0, false); |
| | 981 | |
| | 982 | // stack_trace.index += 1; |
| | 983 | LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); |
| | 984 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); |
| | 985 | |
| | 986 | // return; |
| | 987 | LLVMBuildRetVoid(g->builder); |
| | 988 | |
| | 989 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| | 990 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| | 991 | |
| | 992 | g->return_err_fn = fn_val; |
| | 993 | return fn_val; |
| | 994 | } |
| | 995 | |
| 922 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | 996 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 923 | if (g->safety_crash_err_fn != nullptr) | 997 | if (g->safety_crash_err_fn != nullptr) |
| 924 | return g->safety_crash_err_fn; | 998 | return g->safety_crash_err_fn; |
| ... | @@ -1053,8 +1127,9 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | ... | @@ -1053,8 +1127,9 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { |
| 1053 | err_val, | 1127 | err_val, |
| 1054 | err_ret_trace_val, | 1128 | err_ret_trace_val, |
| 1055 | }; | 1129 | }; |
| 1056 | ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified), | 1130 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified), |
| 1057 | ZigLLVM_FnInlineAuto, ""); | 1131 | ZigLLVM_FnInlineAuto, ""); |
| | 1132 | LLVMSetTailCall(call_instruction, true); |
| 1058 | LLVMBuildUnreachable(g->builder); | 1133 | LLVMBuildUnreachable(g->builder); |
| 1059 | } | 1134 | } |
| 1060 | | 1135 | |
| ... | @@ -1346,36 +1421,19 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns | ... | @@ -1346,36 +1421,19 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 1346 | is_err_return = true; | 1421 | is_err_return = true; |
| 1347 | } | 1422 | } |
| 1348 | if (is_err_return) { | 1423 | if (is_err_return) { |
| 1349 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref; | | |
| 1350 | | | |
| 1351 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer(); | | |
| 1352 | // stack_trace.index += 1; | | |
| 1353 | | | |
| 1354 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); | 1424 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError"); |
| 1355 | | | |
| 1356 | LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); | 1425 | LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block); |
| 1357 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | | |
| 1358 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); | | |
| 1359 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | | |
| 1360 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); | | |
| 1361 | | | |
| 1362 | // stack_trace.instruction_addresses[stack_trace.index % stack_trace_ptr_count] = @instructionPointer(); | | |
| 1363 | LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, ""); | | |
| 1364 | LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), ""); | | |
| 1365 | LLVMValueRef address_indices[] = { | | |
| 1366 | LLVMConstNull(usize_type_ref), | | |
| 1367 | modded_val, | | |
| 1368 | }; | | |
| 1369 | LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, addresses_field_ptr, address_indices, 2, ""); | | |
| 1370 | LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, block_address, usize_type_ref, ""); | | |
| 1371 | gen_store_untyped(g, address_value, address_slot, 0, false); | | |
| 1372 | | | |
| 1373 | // stack_trace.index += 1; | | |
| 1374 | LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), ""); | | |
| 1375 | gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false); | | |
| 1376 | | 1426 | |
| | 1427 | LLVMValueRef return_err_fn = get_return_err_fn(g); |
| | 1428 | LLVMValueRef args[] = { |
| | 1429 | g->cur_err_ret_trace_val, |
| | 1430 | block_address, |
| | 1431 | }; |
| 1377 | LLVMBuildBr(g->builder, return_block); | 1432 | LLVMBuildBr(g->builder, return_block); |
| 1378 | LLVMPositionBuilderAtEnd(g->builder, return_block); | 1433 | LLVMPositionBuilderAtEnd(g->builder, return_block); |
| | 1434 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2, |
| | 1435 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| | 1436 | LLVMSetTailCall(call_instruction, true); |
| 1379 | } | 1437 | } |
| 1380 | if (handle_is_ptr(return_type)) { | 1438 | if (handle_is_ptr(return_type)) { |
| 1381 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { | 1439 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { |