authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-08 17:57:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-08 17:57:29-04:00
logfef06f2142a0f7ec65d3500aff509c74d89bf63b
tree151da8064d7f08e1f56b13c4a2ef73d2148aa450
parent7186e92c86982950d0aa7c0c2deef9ef96bc1264
parentee1a4f4c1d888d1485d8bb13ee0fa756bf729b08

Merge branch 'async-err-ret-traces'

closes #821

6 files changed, 538 insertions(+), 123 deletions(-)

src/all_types.hpp+32-1
...@@ -1656,6 +1656,8 @@ struct CodeGen {...@@ -1656,6 +1656,8 @@ struct CodeGen {
1656 LLVMValueRef coro_save_fn_val;1656 LLVMValueRef coro_save_fn_val;
1657 LLVMValueRef coro_promise_fn_val;1657 LLVMValueRef coro_promise_fn_val;
1658 LLVMValueRef coro_alloc_helper_fn_val;1658 LLVMValueRef coro_alloc_helper_fn_val;
1659 LLVMValueRef merge_err_ret_traces_fn_val;
1660 LLVMValueRef add_error_return_trace_addr_fn_val;
1659 bool error_during_imports;1661 bool error_during_imports;
16601662
1661 const char **clang_argv;1663 const char **clang_argv;
...@@ -2054,6 +2056,8 @@ enum IrInstructionId {...@@ -2054,6 +2056,8 @@ enum IrInstructionId {
2054 IrInstructionIdAwaitBookkeeping,2056 IrInstructionIdAwaitBookkeeping,
2055 IrInstructionIdSaveErrRetAddr,2057 IrInstructionIdSaveErrRetAddr,
2056 IrInstructionIdAddImplicitReturnType,2058 IrInstructionIdAddImplicitReturnType,
2059 IrInstructionIdMergeErrRetTraces,
2060 IrInstructionIdMarkErrRetTracePtr,
2057};2061};
20582062
2059struct IrInstruction {2063struct IrInstruction {
...@@ -2892,6 +2896,11 @@ struct IrInstructionExport {...@@ -2892,6 +2896,11 @@ struct IrInstructionExport {
28922896
2893struct IrInstructionErrorReturnTrace {2897struct IrInstructionErrorReturnTrace {
2894 IrInstruction base;2898 IrInstruction base;
2899
2900 enum Nullable {
2901 Null,
2902 NonNull,
2903 } nullable;
2895};2904};
28962905
2897struct IrInstructionErrorUnion {2906struct IrInstructionErrorUnion {
...@@ -3024,6 +3033,20 @@ struct IrInstructionAddImplicitReturnType {...@@ -3024,6 +3033,20 @@ struct IrInstructionAddImplicitReturnType {
3024 IrInstruction *value;3033 IrInstruction *value;
3025};3034};
30263035
3036struct IrInstructionMergeErrRetTraces {
3037 IrInstruction base;
3038
3039 IrInstruction *coro_promise_ptr;
3040 IrInstruction *src_err_ret_trace_ptr;
3041 IrInstruction *dest_err_ret_trace_ptr;
3042};
3043
3044struct IrInstructionMarkErrRetTracePtr {
3045 IrInstruction base;
3046
3047 IrInstruction *err_ret_trace_ptr;
3048};
3049
3027static const size_t slice_ptr_index = 0;3050static const size_t slice_ptr_index = 0;
3028static const size_t slice_len_index = 1;3051static const size_t slice_len_index = 1;
30293052
...@@ -3033,10 +3056,18 @@ static const size_t maybe_null_index = 1;...@@ -3033,10 +3056,18 @@ static const size_t maybe_null_index = 1;
3033static const size_t err_union_err_index = 0;3056static const size_t err_union_err_index = 0;
3034static const size_t err_union_payload_index = 1;3057static const size_t err_union_payload_index = 1;
30353058
3059// TODO call graph analysis to find out what this number needs to be for every function
3060static const size_t stack_trace_ptr_count = 30;
3061
3062// these belong to the async function
3063#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3064#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3065#define RESULT_FIELD_NAME "result"
3036#define ASYNC_ALLOC_FIELD_NAME "allocFn"3066#define ASYNC_ALLOC_FIELD_NAME "allocFn"
3037#define ASYNC_FREE_FIELD_NAME "freeFn"3067#define ASYNC_FREE_FIELD_NAME "freeFn"
3038#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"3068#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
3039#define RESULT_FIELD_NAME "result"3069// these point to data belonging to the awaiter
3070#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3040#define RESULT_PTR_FIELD_NAME "result_ptr"3071#define RESULT_PTR_FIELD_NAME "result_ptr"
30413072
30423073
src/analyze.cpp+23-3
...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
468468
469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
471 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};471
472 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};472 ZigList<const char *> field_names = {};
473 field_names.append(AWAITER_HANDLE_FIELD_NAME);
474 field_names.append(RESULT_FIELD_NAME);
475 field_names.append(RESULT_PTR_FIELD_NAME);
476 if (g->have_err_ret_tracing) {
477 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
478 field_names.append(ERR_RET_TRACE_FIELD_NAME);
479 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
480 }
481
482 ZigList<TypeTableEntry *> field_types = {};
483 field_types.append(awaiter_handle_type);
484 field_types.append(return_type);
485 field_types.append(result_ptr_type);
486 if (g->have_err_ret_tracing) {
487 field_types.append(get_ptr_to_stack_trace_type(g));
488 field_types.append(g->stack_trace_type);
489 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
490 }
491
492 assert(field_names.length == field_types.length);
473 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));493 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
474 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3);494 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
475495
476 return_type->promise_frame_parent = entry;496 return_type->promise_frame_parent = entry;
477 return entry;497 return entry;
src/codegen.cpp+248-46
...@@ -1114,22 +1114,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {...@@ -1114,22 +1114,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1114 return g->return_address_fn_val;1114 return g->return_address_fn_val;
1115}1115}
11161116
1117static LLVMValueRef get_return_err_fn(CodeGen *g) {1117static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1118 if (g->return_err_fn != nullptr)1118 if (g->add_error_return_trace_addr_fn_val != nullptr)
1119 return g->return_err_fn;1119 return g->add_error_return_trace_addr_fn_val;
1120
1121 assert(g->err_tag_type != nullptr);
11221120
1123 LLVMTypeRef arg_types[] = {1121 LLVMTypeRef arg_types[] = {
1124 // error return trace pointer
1125 get_ptr_to_stack_trace_type(g)->type_ref,1122 get_ptr_to_stack_trace_type(g)->type_ref,
1123 g->builtin_types.entry_usize->type_ref,
1126 };1124 };
1127 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1125 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
11281126
1129 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);1127 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false);
1130 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1128 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1131 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address1129 addLLVMFnAttr(fn_val, "alwaysinline");
1132 addLLVMFnAttr(fn_val, "cold");
1133 LLVMSetLinkage(fn_val, LLVMInternalLinkage);1130 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1134 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1131 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1135 addLLVMFnAttr(fn_val, "nounwind");1132 addLLVMFnAttr(fn_val, "nounwind");
...@@ -1151,6 +1148,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1151,6 +1148,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1151 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;1148 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
11521149
1153 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);1150 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1151 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
1152
1154 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;1153 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1155 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");1154 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
1156 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;1155 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
...@@ -1172,15 +1171,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1172,15 +1171,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1172 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");1171 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
1173 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");1172 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
11741173
1175 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1176 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1177 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1178
1179 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
1180 gen_store_untyped(g, address_value, address_slot, 0, false);1174 gen_store_untyped(g, address_value, address_slot, 0, false);
11811175
1182 // stack_trace.index += 1;1176 // stack_trace.index += 1;
1183 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");1177 LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1184 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);1178 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
11851179
1186 // return;1180 // return;
...@@ -1189,6 +1183,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1189,6 +1183,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1189 LLVMPositionBuilderAtEnd(g->builder, prev_block);1183 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1190 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1184 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
11911185
1186 g->add_error_return_trace_addr_fn_val = fn_val;
1187 return fn_val;
1188}
1189
1190static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1191 if (g->merge_err_ret_traces_fn_val)
1192 return g->merge_err_ret_traces_fn_val;
1193
1194 assert(g->stack_trace_type != nullptr);
1195
1196 LLVMTypeRef param_types[] = {
1197 get_ptr_to_stack_trace_type(g)->type_ref,
1198 get_ptr_to_stack_trace_type(g)->type_ref,
1199 };
1200 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1201
1202 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1203 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1204 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1205 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1206 addLLVMFnAttr(fn_val, "nounwind");
1207 add_uwtable_attr(g, fn_val);
1208 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1209 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1210 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1211 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1212 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1213 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1214 if (g->build_mode == BuildModeDebug) {
1215 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1216 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1217 }
1218
1219 // this is above the ZigLLVMClearCurrentDebugLocation
1220 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1221
1222 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1223 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1224 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1225 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1226 ZigLLVMClearCurrentDebugLocation(g->builder);
1227
1228 // var frame_index: usize = undefined;
1229 // var frames_left: usize = undefined;
1230 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1231 // frame_index = 0;
1232 // frames_left = src_stack_trace.index;
1233 // if (frames_left == 0) return;
1234 // } else {
1235 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1236 // frames_left = src_stack_trace.instruction_addresses.len;
1237 // }
1238 // while (true) {
1239 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1240 // frames_left -= 1;
1241 // if (frames_left == 0) return;
1242 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1243 // }
1244 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1245
1246 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index");
1247 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left");
1248
1249 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1250 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1251
1252 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1253 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1254 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1255 (unsigned)src_index_field_index, "");
1256 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1257 (unsigned)src_addresses_field_index, "");
1258 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1259 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1260 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1261 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1262 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1263 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1264 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1265 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1266 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1267 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1268 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1269 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1270 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1271
1272 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1273 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
1274 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1275 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1276 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1277 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1278
1279 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1280 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
1281 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1282 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1283 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1284 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1285 LLVMBuildBr(g->builder, loop_block);
1286
1287 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1288 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1289 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1290 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1291 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1292 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1293 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1294 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1295 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1296 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1297 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1298
1299 LLVMPositionBuilderAtEnd(g->builder, return_block);
1300 LLVMBuildRetVoid(g->builder);
1301
1302 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1303 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1304 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1305 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1306 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1307 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1308 LLVMBuildBr(g->builder, loop_block);
1309
1310 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1311 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1312
1313 g->merge_err_ret_traces_fn_val = fn_val;
1314 return fn_val;
1315
1316}
1317
1318static LLVMValueRef get_return_err_fn(CodeGen *g) {
1319 if (g->return_err_fn != nullptr)
1320 return g->return_err_fn;
1321
1322 assert(g->err_tag_type != nullptr);
1323
1324 LLVMTypeRef arg_types[] = {
1325 // error return trace pointer
1326 get_ptr_to_stack_trace_type(g)->type_ref,
1327 };
1328 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
1329
1330 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
1331 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1332 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address
1333 addLLVMFnAttr(fn_val, "cold");
1334 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1335 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1336 addLLVMFnAttr(fn_val, "nounwind");
1337 add_uwtable_attr(g, fn_val);
1338 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1339 if (g->build_mode == BuildModeDebug) {
1340 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1341 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1342 }
1343
1344 // this is above the ZigLLVMClearCurrentDebugLocation
1345 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1346
1347 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1348 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1349 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1350 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1351 ZigLLVMClearCurrentDebugLocation(g->builder);
1352
1353 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1354
1355 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1356 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1357 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1358 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1359
1360 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1361 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1362 LLVMBuildRetVoid(g->builder);
1363
1364 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1365 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1366
1192 g->return_err_fn = fn_val;1367 g->return_err_fn = fn_val;
1193 return fn_val;1368 return fn_val;
1194}1369}
...@@ -1641,7 +1816,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut...@@ -1641,7 +1816,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
1641 };1816 };
1642 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,1817 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1643 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");1818 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1644 LLVMSetTailCall(call_instruction, true);
1645 return call_instruction;1819 return call_instruction;
1646}1820}
16471821
...@@ -4204,6 +4378,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -4204,6 +4378,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4204 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");4378 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
4205}4379}
42064380
4381static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
4382 IrInstructionMergeErrRetTraces *instruction)
4383{
4384 assert(g->have_err_ret_tracing);
4385
4386 LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
4387 LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
4388
4389 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
4390 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4391 return nullptr;
4392}
4393
4394static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable,
4395 IrInstructionMarkErrRetTracePtr *instruction)
4396{
4397 assert(g->have_err_ret_tracing);
4398 g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr);
4399 return nullptr;
4400}
4401
4207static void set_debug_location(CodeGen *g, IrInstruction *instruction) {4402static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
4208 AstNode *source_node = instruction->source_node;4403 AstNode *source_node = instruction->source_node;
4209 Scope *scope = instruction->scope;4404 Scope *scope = instruction->scope;
...@@ -4421,6 +4616,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4421,6 +4616,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4421 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);4616 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4422 case IrInstructionIdSaveErrRetAddr:4617 case IrInstructionIdSaveErrRetAddr:
4423 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);4618 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4619 case IrInstructionIdMergeErrRetTraces:
4620 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
4621 case IrInstructionIdMarkErrRetTracePtr:
4622 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
4424 }4623 }
4425 zig_unreachable();4624 zig_unreachable();
4426}4625}
...@@ -5310,38 +5509,14 @@ static void do_code_gen(CodeGen *g) {...@@ -5310,38 +5509,14 @@ static void do_code_gen(CodeGen *g) {
5310 g->cur_err_ret_trace_val_arg = nullptr;5509 g->cur_err_ret_trace_val_arg = nullptr;
5311 }5510 }
53125511
5512 // error return tracing setup
5313 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;5513 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5314 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&5514 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
5315 (is_async || !have_err_ret_trace_arg);5515 LLVMValueRef err_ret_array_val = nullptr;
5316 if (have_err_ret_trace_stack) {5516 if (have_err_ret_trace_stack) {
5317 // TODO call graph analysis to find out what this number needs to be for every function5517 TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
5318 static const size_t stack_trace_ptr_count = 30;5518 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
5319
5320 TypeTableEntry *usize = g->builtin_types.entry_usize;
5321 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5322 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
5323 get_abi_alignment(g, array_type));
5324 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));5519 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
5325 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5326 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5327 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5328
5329 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5330 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5331
5332 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5333 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5334 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5335 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5336 LLVMValueRef indices[] = {zero, zero};
5337 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5338 indices, 2, "");
5339 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
5340 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
5341
5342 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5343 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5344 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5345 } else {5520 } else {
5346 g->cur_err_ret_trace_val_stack = nullptr;5521 g->cur_err_ret_trace_val_stack = nullptr;
5347 }5522 }
...@@ -5436,6 +5611,31 @@ static void do_code_gen(CodeGen *g) {...@@ -5436,6 +5611,31 @@ static void do_code_gen(CodeGen *g) {
5436 }5611 }
5437 }5612 }
54385613
5614 // finishing error return trace setup. we have to do this after all the allocas.
5615 if (have_err_ret_trace_stack) {
5616 TypeTableEntry *usize = g->builtin_types.entry_usize;
5617 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5618 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5619 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5620
5621 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5622 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5623
5624 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5625 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5626 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5627 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5628 LLVMValueRef indices[] = {zero, zero};
5629 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5630 indices, 2, "");
5631 TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false);
5632 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type);
5633
5634 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5635 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5636 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5637 }
5638
5439 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;5639 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
54405640
5441 // create debug variable declarations for parameters5641 // create debug variable declarations for parameters
...@@ -5943,6 +6143,8 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5943,6 +6143,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
5943 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);6143 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5944 Buf *contents = buf_alloc();6144 Buf *contents = buf_alloc();
59456145
6146 // Modifications to this struct must be coordinated with code that does anything with
6147 // g->stack_trace_type. There are hard-coded references to the field indexes.
5946 buf_append_str(contents,6148 buf_append_str(contents,
5947 "pub const StackTrace = struct {\n"6149 "pub const StackTrace = struct {\n"
5948 " index: usize,\n"6150 " index: usize,\n"
src/ir.cpp+168-72
...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
725 return IrInstructionIdAddImplicitReturnType;725 return IrInstructionIdAddImplicitReturnType;
726}726}
727727
728static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
729 return IrInstructionIdMergeErrRetTraces;
730}
731
732static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
733 return IrInstructionIdMarkErrRetTracePtr;
734}
735
728template<typename T>736template<typename T>
729static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {737static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
730 T *special_instruction = allocate<T>(1);738 T *special_instruction = allocate<T>(1);
...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
956 return &const_instruction->base;964 return &const_instruction->base;
957}965}
958966
959static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
960 TypeTableEntry *return_type)
961{
962 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
963
964 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
965 const_instruction->base.value.type = struct_type;
966 const_instruction->base.value.special = ConstValSpecialStatic;
967 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
968 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
969 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
970 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
971 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
972 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
973 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
974 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
975 return &const_instruction->base;
976}
977
978static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,967static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
979 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)968 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
980{969{
...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2495 return &instruction->base;2484 return &instruction->base;
2496}2485}
24972486
2498static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {2487static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2499 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);2488 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2489 instruction->nullable = nullable;
25002490
2501 return &instruction->base;2491 return &instruction->base;
2502}2492}
...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
2717 return &instruction->base;2707 return &instruction->base;
2718}2708}
27192709
2710static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
2711 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
2712{
2713 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
2714 instruction->coro_promise_ptr = coro_promise_ptr;
2715 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
2716 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
2717
2718 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
2719 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
2720 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
2721
2722 return &instruction->base;
2723}
2724
2725static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
2726 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
2727 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
2728
2729 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
2730
2731 return &instruction->base;
2732}
2733
2720static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2734static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2721 results[ReturnKindUnconditional] = 0;2735 results[ReturnKindUnconditional] = 0;
2722 results[ReturnKindError] = 0;2736 results[ReturnKindError] = 0;
...@@ -2822,34 +2836,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2822,34 +2836,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2822 // the above blocks are rendered by ir_gen after the rest of codegen2836 // the above blocks are rendered by ir_gen after the rest of codegen
2823}2837}
28242838
2825static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2826 if (!g->have_err_ret_tracing)
2827 return false;
2828 FnTableEntry *fn_entry = exec_fn_entry(exec);
2829 if (fn_entry == nullptr)
2830 return false;
2831 if (exec->is_inline)
2832 return false;
2833 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2834}
2835
2836static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2837 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2838 return;
2839
2840 bool is_async = exec_is_async(irb->exec);
2841
2842 if (is_async) {
2843 //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2844 //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
2845 //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2846 //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2847 return;
2848 }
2849
2850 ir_build_save_err_ret_addr(irb, scope, node);
2851}
2852
2853static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2839static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2854 assert(node->type == NodeTypeReturnExpr);2840 assert(node->type == NodeTypeReturnExpr);
28552841
...@@ -2895,8 +2881,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2895,8 +2881,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28952881
2896 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);2882 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
28972883
2884 bool should_inline = ir_should_inline(irb->exec, scope);
2898 IrInstruction *is_comptime;2885 IrInstruction *is_comptime;
2899 if (ir_should_inline(irb->exec, scope)) {2886 if (should_inline) {
2900 is_comptime = ir_build_const_bool(irb, scope, node, true);2887 is_comptime = ir_build_const_bool(irb, scope, node, true);
2901 } else {2888 } else {
2902 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);2889 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
...@@ -2909,7 +2896,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2909,7 +2896,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2909 if (have_err_defers) {2896 if (have_err_defers) {
2910 ir_gen_defers_for_block(irb, scope, outer_scope, true);2897 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2911 }2898 }
2912 ir_gen_save_err_ret_addr(irb, scope, node);2899 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2900 ir_build_save_err_ret_addr(irb, scope, node);
2901 }
2913 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2902 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
29142903
2915 ir_set_cursor_at_end_and_append_block(irb, ok_block);2904 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -2938,7 +2927,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2938,7 +2927,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2938 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");2927 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
2939 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");2928 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
2940 IrInstruction *is_comptime;2929 IrInstruction *is_comptime;
2941 if (ir_should_inline(irb->exec, scope)) {2930 bool should_inline = ir_should_inline(irb->exec, scope);
2931 if (should_inline) {
2942 is_comptime = ir_build_const_bool(irb, scope, node, true);2932 is_comptime = ir_build_const_bool(irb, scope, node, true);
2943 } else {2933 } else {
2944 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);2934 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
...@@ -2948,7 +2938,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2948,7 +2938,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2948 ir_set_cursor_at_end_and_append_block(irb, return_block);2938 ir_set_cursor_at_end_and_append_block(irb, return_block);
2949 ir_gen_defers_for_block(irb, scope, outer_scope, true);2939 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2950 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2940 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2951 ir_gen_save_err_ret_addr(irb, scope, node);2941 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2942 ir_build_save_err_ret_addr(irb, scope, node);
2943 }
2952 ir_gen_async_return(irb, scope, node, err_val, false);2944 ir_gen_async_return(irb, scope, node, err_val, false);
29532945
2954 ir_set_cursor_at_end_and_append_block(irb, continue_block);2946 ir_set_cursor_at_end_and_append_block(irb, continue_block);
...@@ -4242,7 +4234,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4242,7 +4234,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4242 }4234 }
4243 case BuiltinFnIdErrorReturnTrace:4235 case BuiltinFnIdErrorReturnTrace:
4244 {4236 {
4245 return ir_build_error_return_trace(irb, scope, node);4237 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4246 }4238 }
4247 case BuiltinFnIdAtomicRmw:4239 case BuiltinFnIdAtomicRmw:
4248 {4240 {
...@@ -6125,6 +6117,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6125,6 +6117,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6125 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6117 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6126 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);6118 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
61276119
6120 if (irb->codegen->have_err_ret_tracing) {
6121 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6122 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6123 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6124 ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6125 }
6126
6128 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6127 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6129 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,6128 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
6130 awaiter_handle_field_name);6129 awaiter_handle_field_name);
...@@ -6148,10 +6147,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6148,10 +6147,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6148 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);6147 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6149 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");6148 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6150 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");6149 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6151 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");6150 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
6152 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);6151 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
61536152
6154 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);6153 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6154 if (irb->codegen->have_err_ret_tracing) {
6155 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6156 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
6157 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6158 ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
6159 }
6155 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6160 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6156 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);6161 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6157 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);6162 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
...@@ -6407,6 +6412,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6407,6 +6412,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6407 IrInstruction *coro_id;6412 IrInstruction *coro_id;
6408 IrInstruction *u8_ptr_type;6413 IrInstruction *u8_ptr_type;
6409 IrInstruction *const_bool_false;6414 IrInstruction *const_bool_false;
6415 IrInstruction *coro_promise_ptr;
6416 IrInstruction *err_ret_trace_ptr;
6410 TypeTableEntry *return_type;6417 TypeTableEntry *return_type;
6411 Buf *result_ptr_field_name;6418 Buf *result_ptr_field_name;
6412 VariableTableEntry *coro_size_var;6419 VariableTableEntry *coro_size_var;
...@@ -6417,9 +6424,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6417,9 +6424,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6417 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6424 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
64186425
6419 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;6426 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6420 IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type);6427 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6421 ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init);6428 TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
6422 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);6429 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
6430 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
6431 ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
6432 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
64236433
6424 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6434 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6425 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);6435 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
...@@ -6452,7 +6462,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6452,7 +6462,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6452 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6462 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6453 // we can return undefined here, because the caller passes a pointer to the error struct field6463 // we can return undefined here, because the caller passes a pointer to the error struct field
6454 // in the error union result, and we populate it in case of allocation failure.6464 // in the error union result, and we populate it in case of allocation failure.
6455 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6456 ir_build_return(irb, coro_scope, node, undef);6465 ir_build_return(irb, coro_scope, node, undef);
64576466
6458 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);6467 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
...@@ -6460,13 +6469,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6460,13 +6469,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6460 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);6469 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
64616470
6462 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6471 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6463 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr,6472 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6464 awaiter_handle_field_name);6473 awaiter_handle_field_name);
6474 ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value);
6465 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6475 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6466 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name);6476 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6467 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6477 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6468 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name);6478 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);6479 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6480 if (irb->codegen->have_err_ret_tracing) {
6481 // initialize the error return trace
6482 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
6483 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
6484
6485 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6486 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
6487 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
6488
6489 // coordinate with builtin.zig
6490 Buf *index_name = buf_create_from_str("index");
6491 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
6492 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6493 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
6494
6495 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
6496 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
6497
6498 IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
6499 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
6500 }
64706501
64716502
6472 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");6503 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
...@@ -6517,6 +6548,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6517,6 +6548,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6517 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);6548 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
6518 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);6549 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
6519 }6550 }
6551 if (irb->codegen->have_err_ret_tracing) {
6552 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6553 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6554 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
6555 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
6556 }
6520 ir_build_br(irb, scope, node, check_free_block, const_bool_false);6557 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
65216558
6522 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);6559 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
...@@ -11579,18 +11616,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {...@@ -11579,18 +11616,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
11579static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11616static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11580 IrInstructionErrorReturnTrace *instruction)11617 IrInstructionErrorReturnTrace *instruction)
11581{11618{
11582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11619 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
11583 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11620 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11584 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {11621 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11622 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11586 out_val->data.x_maybe = nullptr;11623 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11624 out_val->data.x_maybe = nullptr;
11625 return nullable_type;
11626 }
11627 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11628 instruction->base.source_node, instruction->nullable);
11629 ir_link_new_instruction(new_instruction, &instruction->base);
11587 return nullable_type;11630 return nullable_type;
11631 } else {
11632 assert(ira->codegen->have_err_ret_tracing);
11633 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11634 instruction->base.source_node, instruction->nullable);
11635 ir_link_new_instruction(new_instruction, &instruction->base);
11636 return get_ptr_to_stack_trace_type(ira->codegen);
11588 }11637 }
11589
11590 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11591 instruction->base.source_node);
11592 ir_link_new_instruction(new_instruction, &instruction->base);
11593 return nullable_type;
11594}11638}
1159511639
11596static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,11640static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
...@@ -13072,6 +13116,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -13072,6 +13116,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
13072{13116{
13073 if (!is_slice(bare_struct_type)) {13117 if (!is_slice(bare_struct_type)) {
13074 ScopeDecls *container_scope = get_container_scope(bare_struct_type);13118 ScopeDecls *container_scope = get_container_scope(bare_struct_type);
13119 assert(container_scope != nullptr);
13075 auto entry = container_scope->decl_table.maybe_get(field_name);13120 auto entry = container_scope->decl_table.maybe_get(field_name);
13076 Tld *tld = entry ? entry->value : nullptr;13121 Tld *tld = entry ? entry->value : nullptr;
13077 if (tld && tld->id == TldIdFn) {13122 if (tld && tld->id == TldIdFn) {
...@@ -17904,6 +17949,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17904,6 +17949,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17904 return out_val->type;17949 return out_val->type;
17905}17950}
1790617951
17952static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
17953 IrInstructionMergeErrRetTraces *instruction)
17954{
17955 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other;
17956 if (type_is_invalid(coro_promise_ptr->value.type))
17957 return ira->codegen->builtin_types.entry_invalid;
17958
17959 assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer);
17960 TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
17961 assert(promise_frame_type->id == TypeTableEntryIdStruct);
17962 TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
17963
17964 if (!type_can_fail(promise_result_type)) {
17965 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17966 out_val->type = ira->codegen->builtin_types.entry_void;
17967 return out_val->type;
17968 }
17969
17970 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other;
17971 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
17972 return ira->codegen->builtin_types.entry_invalid;
17973
17974 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other;
17975 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
17976 return ira->codegen->builtin_types.entry_invalid;
17977
17978 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
17979 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
17980 ir_link_new_instruction(result, &instruction->base);
17981 result->value.type = ira->codegen->builtin_types.entry_void;
17982 return result->value.type;
17983}
17984
17907static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {17985static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
17908 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,17986 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
17909 instruction->base.source_node);17987 instruction->base.source_node);
...@@ -17912,6 +17990,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,...@@ -17912,6 +17990,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,
17912 return result->value.type;17990 return result->value.type;
17913}17991}
1791417992
17993static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
17994 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other;
17995 if (type_is_invalid(err_ret_trace_ptr->value.type))
17996 return ira->codegen->builtin_types.entry_invalid;
17997
17998 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
17999 instruction->base.source_node, err_ret_trace_ptr);
18000 ir_link_new_instruction(result, &instruction->base);
18001 result->value.type = ira->codegen->builtin_types.entry_void;
18002 return result->value.type;
18003}
18004
17915static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {18005static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17916 switch (instruction->id) {18006 switch (instruction->id) {
17917 case IrInstructionIdInvalid:18007 case IrInstructionIdInvalid:
...@@ -18155,6 +18245,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18155,6 +18245,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18155 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);18245 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
18156 case IrInstructionIdAddImplicitReturnType:18246 case IrInstructionIdAddImplicitReturnType:
18157 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);18247 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
18248 case IrInstructionIdMergeErrRetTraces:
18249 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
18250 case IrInstructionIdMarkErrRetTracePtr:
18251 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
18158 }18252 }
18159 zig_unreachable();18253 zig_unreachable();
18160}18254}
...@@ -18282,6 +18376,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18282,6 +18376,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18282 case IrInstructionIdAwaitBookkeeping:18376 case IrInstructionIdAwaitBookkeeping:
18283 case IrInstructionIdSaveErrRetAddr:18377 case IrInstructionIdSaveErrRetAddr:
18284 case IrInstructionIdAddImplicitReturnType:18378 case IrInstructionIdAddImplicitReturnType:
18379 case IrInstructionIdMergeErrRetTraces:
18380 case IrInstructionIdMarkErrRetTracePtr:
18285 return true;18381 return true;
1828618382
18287 case IrInstructionIdPhi:18383 case IrInstructionIdPhi:
src/ir_print.cpp+32-1
...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
1024}1024}
10251025
1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1027 fprintf(irp->f, "@errorReturnTrace()");1027 fprintf(irp->f, "@errorReturnTrace(");
1028 switch (instruction->nullable) {
1029 case IrInstructionErrorReturnTrace::Null:
1030 fprintf(irp->f, "Null");
1031 break;
1032 case IrInstructionErrorReturnTrace::NonNull:
1033 fprintf(irp->f, "NonNull");
1034 break;
1035 }
1036 fprintf(irp->f, ")");
1028}1037}
10291038
1030static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {1039static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
1179 fprintf(irp->f, ")");1188 fprintf(irp->f, ")");
1180}1189}
11811190
1191static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1192 fprintf(irp->f, "@mergeErrRetTraces(");
1193 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1194 fprintf(irp->f, ",");
1195 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1196 fprintf(irp->f, ",");
1197 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1198 fprintf(irp->f, ")");
1199}
1200
1201static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1202 fprintf(irp->f, "@markErrRetTracePtr(");
1203 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1204 fprintf(irp->f, ")");
1205}
1206
1182static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1207static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1183 ir_print_prefix(irp, instruction);1208 ir_print_prefix(irp, instruction);
1184 switch (instruction->id) {1209 switch (instruction->id) {
...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1559 case IrInstructionIdAddImplicitReturnType:1584 case IrInstructionIdAddImplicitReturnType:
1560 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);1585 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1561 break;1586 break;
1587 case IrInstructionIdMergeErrRetTraces:
1588 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
1589 break;
1590 case IrInstructionIdMarkErrRetTracePtr:
1591 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
1592 break;
1562 }1593 }
1563 fprintf(irp->f, "\n");1594 fprintf(irp->f, "\n");
1564}1595}
test/cases/coroutines.zig+35
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
34
4var x: i32 = 1;5var x: i32 = 1;
...@@ -189,3 +190,37 @@ async fn failing() !void {...@@ -189,3 +190,37 @@ async fn failing() !void {
189 suspend;190 suspend;
190 return error.Fail;191 return error.Fail;
191}192}
193
194test "error return trace across suspend points - early return" {
195 const p = nonFailing();
196 resume p;
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 cancel p2;
199}
200
201test "error return trace across suspend points - async return" {
202 const p = nonFailing();
203 const p2 = try async<std.debug.global_allocator> printTrace(p);
204 resume p;
205 cancel p2;
206}
207
208fn nonFailing() promise->error!void {
209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210}
211
212async fn suspendThenFail() error!void {
213 suspend;
214 return error.Fail;
215}
216
217async fn printTrace(p: promise->error!void) void {
218 (await p) catch |e| {
219 std.debug.assert(e == error.Fail);
220 if (@errorReturnTrace()) |trace| {
221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
224 }
225 };
226}