authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-29 00:24:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-04-08 16:04:48-04:00
logd26905c102f45382a5aa4bf59deda0ccc8c6e50f
treee684112b364f7b896818c2d64cfb6da2cabc5495
parent7186e92c86982950d0aa7c0c2deef9ef96bc1264

error return traces for the early return case

it would work but LLVM is not correctly spilling the addresses. See #821

5 files changed, 375 insertions(+), 76 deletions(-)

src/all_types.hpp+19
......@@ -1656,6 +1656,8 @@ struct CodeGen {
16561656 LLVMValueRef coro_save_fn_val;
16571657 LLVMValueRef coro_promise_fn_val;
16581658 LLVMValueRef coro_alloc_helper_fn_val;
1659 LLVMValueRef merge_err_ret_traces_fn_val;
1660 LLVMValueRef add_error_return_trace_addr_fn_val;
16591661 bool error_during_imports;
16601662
16611663 const char **clang_argv;
......@@ -2054,6 +2056,7 @@ enum IrInstructionId {
20542056 IrInstructionIdAwaitBookkeeping,
20552057 IrInstructionIdSaveErrRetAddr,
20562058 IrInstructionIdAddImplicitReturnType,
2059 IrInstructionIdMergeErrRetTraces,
20572060};
20582061
20592062struct IrInstruction {
......@@ -2892,6 +2895,11 @@ struct IrInstructionExport {
28922895
28932896struct IrInstructionErrorReturnTrace {
28942897 IrInstruction base;
2898
2899 enum Nullable {
2900 Null,
2901 NonNull,
2902 } nullable;
28952903};
28962904
28972905struct IrInstructionErrorUnion {
......@@ -3024,6 +3032,13 @@ struct IrInstructionAddImplicitReturnType {
30243032 IrInstruction *value;
30253033};
30263034
3035struct IrInstructionMergeErrRetTraces {
3036 IrInstruction base;
3037
3038 IrInstruction *coro_promise_ptr;
3039 TypeStructField *resolved_field;
3040};
3041
30273042static const size_t slice_ptr_index = 0;
30283043static const size_t slice_len_index = 1;
30293044
......@@ -3033,11 +3048,15 @@ static const size_t maybe_null_index = 1;
30333048static const size_t err_union_err_index = 0;
30343049static const size_t err_union_payload_index = 1;
30353050
3051// TODO call graph analysis to find out what this number needs to be for every function
3052static const size_t stack_trace_ptr_count = 30;
3053
30363054#define ASYNC_ALLOC_FIELD_NAME "allocFn"
30373055#define ASYNC_FREE_FIELD_NAME "freeFn"
30383056#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
30393057#define RESULT_FIELD_NAME "result"
30403058#define RESULT_PTR_FIELD_NAME "result_ptr"
3059#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
30413060
30423061
30433062enum FloatMode {
src/analyze.cpp+19-3
......@@ -468,10 +468,26 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
468468
469469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
470470 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};
472 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
471
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 }
479
480 ZigList<TypeTableEntry *> field_types = {};
481 field_types.append(awaiter_handle_type);
482 field_types.append(return_type);
483 field_types.append(result_ptr_type);
484 if (g->have_err_ret_tracing) {
485 field_types.append(get_ptr_to_stack_trace_type(g));
486 }
487
488 assert(field_names.length == field_types.length);
473489 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);
490 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
475491
476492 return_type->promise_frame_parent = entry;
477493 return entry;
src/codegen.cpp+217-23
......@@ -1114,22 +1114,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
11141114 return g->return_address_fn_val;
11151115}
11161116
1117static LLVMValueRef get_return_err_fn(CodeGen *g) {
1118 if (g->return_err_fn != nullptr)
1119 return g->return_err_fn;
1120
1121 assert(g->err_tag_type != nullptr);
1117static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1118 if (g->add_error_return_trace_addr_fn_val != nullptr)
1119 return g->add_error_return_trace_addr_fn_val;
11221120
11231121 LLVMTypeRef arg_types[] = {
1124 // error return trace pointer
11251122 get_ptr_to_stack_trace_type(g)->type_ref,
1123 g->builtin_types.entry_usize->type_ref,
11261124 };
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);
11301128 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 address
1132 addLLVMFnAttr(fn_val, "cold");
1129 addLLVMFnAttr(fn_val, "alwaysinline");
11331130 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
11341131 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
11351132 addLLVMFnAttr(fn_val, "nounwind");
......@@ -1151,6 +1148,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
11511148 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
11521149
11531150 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1151 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
1152
11541153 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
11551154 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
11561155 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) {
11721171 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
11731172 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, "");
11801174 gen_store_untyped(g, address_value, address_slot, 0, false);
11811175
11821176 // 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), "");
11841178 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
11851179
11861180 // return;
......@@ -1189,6 +1183,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
11891183 LLVMPositionBuilderAtEnd(g->builder, prev_block);
11901184 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 LLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, "");
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 LLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, "");
1362 LLVMBuildRetVoid(g->builder);
1363
1364 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1365 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1366
11921367 g->return_err_fn = fn_val;
11931368 return fn_val;
11941369}
......@@ -1641,7 +1816,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
16411816 };
16421817 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
16431818 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1644 LLVMSetTailCall(call_instruction, true);
16451819 return call_instruction;
16461820}
16471821
......@@ -4204,6 +4378,22 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
42044378 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
42054379}
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 coro_promise_ptr = ir_llvm_value(g, instruction->coro_promise_ptr);
4387 TypeStructField *field = instruction->resolved_field;
4388 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, coro_promise_ptr, field->gen_index, "");
4389 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, ptr_field_ptr, "");
4390 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
4391
4392 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
4393 LLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, "");
4394 return nullptr;
4395}
4396
42074397static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
42084398 AstNode *source_node = instruction->source_node;
42094399 Scope *scope = instruction->scope;
......@@ -4421,6 +4611,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
44214611 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
44224612 case IrInstructionIdSaveErrRetAddr:
44234613 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4614 case IrInstructionIdMergeErrRetTraces:
4615 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
44244616 }
44254617 zig_unreachable();
44264618}
......@@ -5313,12 +5505,12 @@ static void do_code_gen(CodeGen *g) {
53135505 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
53145506 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
53155507 (is_async || !have_err_ret_trace_arg);
5316 if (have_err_ret_trace_stack) {
5317 // TODO call graph analysis to find out what this number needs to be for every function
5318 static const size_t stack_trace_ptr_count = 30;
5319
5508 bool have_exactly_one_err_ret_value = !have_err_ret_trace_stack && g->have_err_ret_tracing && is_async &&
5509 type_can_fail(fn_table_entry->type_entry->data.fn.fn_type_id.return_type);
5510 if (have_err_ret_trace_stack || have_exactly_one_err_ret_value) {
53205511 TypeTableEntry *usize = g->builtin_types.entry_usize;
5321 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5512 uint32_t ret_addr_count = have_exactly_one_err_ret_value ? 1 : stack_trace_ptr_count;
5513 TypeTableEntry *array_type = get_array_type(g, usize, ret_addr_count);
53225514 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
53235515 get_abi_alignment(g, array_type));
53245516 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));
......@@ -5341,7 +5533,7 @@ static void do_code_gen(CodeGen *g) {
53415533
53425534 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
53435535 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));
5536 gen_store(g, LLVMConstInt(usize->type_ref, ret_addr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
53455537 } else {
53465538 g->cur_err_ret_trace_val_stack = nullptr;
53475539 }
......@@ -5943,6 +6135,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
59436135 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
59446136 Buf *contents = buf_alloc();
59456137
6138 // Modifications to this struct must be coordinated with code that does anything with
6139 // g->stack_trace_type. There are hard-coded references to the field indexes.
59466140 buf_append_str(contents,
59476141 "pub const StackTrace = struct {\n"
59486142 " index: usize,\n"
src/ir.cpp+97-49
......@@ -725,6 +725,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
725725 return IrInstructionIdAddImplicitReturnType;
726726}
727727
728static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
729 return IrInstructionIdMergeErrRetTraces;
730}
731
728732template<typename T>
729733static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
730734 T *special_instruction = allocate<T>(1);
......@@ -972,6 +976,12 @@ static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope,
972976 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
973977 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
974978 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
979 if (irb->codegen->have_err_ret_tracing) {
980 assert(struct_type->data.structure.src_field_count == 4);
981
982 const_instruction->base.value.data.x_struct.fields[3].type = struct_type->data.structure.fields[3].type_entry;
983 const_instruction->base.value.data.x_struct.fields[3].special = ConstValSpecialUndef;
984 }
975985 return &const_instruction->base;
976986}
977987
......@@ -2495,8 +2505,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
24952505 return &instruction->base;
24962506}
24972507
2498static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2508static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
24992509 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2510 instruction->nullable = nullable;
25002511
25012512 return &instruction->base;
25022513}
......@@ -2717,6 +2728,18 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
27172728 return &instruction->base;
27182729}
27192730
2731static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
2732 IrInstruction *coro_promise_ptr, TypeStructField *resolved_field)
2733{
2734 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
2735 instruction->coro_promise_ptr = coro_promise_ptr;
2736 instruction->resolved_field = resolved_field;
2737
2738 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
2739
2740 return &instruction->base;
2741}
2742
27202743static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
27212744 results[ReturnKindUnconditional] = 0;
27222745 results[ReturnKindError] = 0;
......@@ -2822,34 +2845,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
28222845 // the above blocks are rendered by ir_gen after the rest of codegen
28232846}
28242847
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
28532848static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
28542849 assert(node->type == NodeTypeReturnExpr);
28552850
......@@ -2895,8 +2890,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28952890
28962891 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
28972892
2893 bool should_inline = ir_should_inline(irb->exec, scope);
28982894 IrInstruction *is_comptime;
2899 if (ir_should_inline(irb->exec, scope)) {
2895 if (should_inline) {
29002896 is_comptime = ir_build_const_bool(irb, scope, node, true);
29012897 } else {
29022898 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
......@@ -2909,7 +2905,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29092905 if (have_err_defers) {
29102906 ir_gen_defers_for_block(irb, scope, outer_scope, true);
29112907 }
2912 ir_gen_save_err_ret_addr(irb, scope, node);
2908 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2909 ir_build_save_err_ret_addr(irb, scope, node);
2910 }
29132911 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
29142912
29152913 ir_set_cursor_at_end_and_append_block(irb, ok_block);
......@@ -2938,7 +2936,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29382936 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
29392937 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
29402938 IrInstruction *is_comptime;
2941 if (ir_should_inline(irb->exec, scope)) {
2939 bool should_inline = ir_should_inline(irb->exec, scope);
2940 if (should_inline) {
29422941 is_comptime = ir_build_const_bool(irb, scope, node, true);
29432942 } else {
29442943 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
......@@ -2948,7 +2947,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
29482947 ir_set_cursor_at_end_and_append_block(irb, return_block);
29492948 ir_gen_defers_for_block(irb, scope, outer_scope, true);
29502949 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2951 ir_gen_save_err_ret_addr(irb, scope, node);
2950 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2951 ir_build_save_err_ret_addr(irb, scope, node);
2952 }
29522953 ir_gen_async_return(irb, scope, node, err_val, false);
29532954
29542955 ir_set_cursor_at_end_and_append_block(irb, continue_block);
......@@ -4242,7 +4243,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42424243 }
42434244 case BuiltinFnIdErrorReturnTrace:
42444245 {
4245 return ir_build_error_return_trace(irb, scope, node);
4246 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
42464247 }
42474248 case BuiltinFnIdAtomicRmw:
42484249 {
......@@ -6148,10 +6149,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61486149 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
61496150 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
61506151 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6151 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");
6152 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
61526153 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
61536154
61546155 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6156 if (irb->codegen->have_err_ret_tracing) {
6157 ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, nullptr);
6158 }
61556159 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
61566160 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
61576161 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
......@@ -6460,13 +6464,19 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
64606464 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
64616465
64626466 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,
6467 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
64646468 awaiter_handle_field_name);
64656469 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);
6470 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
64676471 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);
6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6472 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6473 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6474 if (irb->codegen->have_err_ret_tracing) {
6475 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
6476 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6477 IrInstruction *coro_err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6478 ir_build_store_ptr(irb, scope, node, coro_err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6479 }
64706480
64716481
64726482 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
......@@ -11579,18 +11589,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
1157911589static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1158011590 IrInstructionErrorReturnTrace *instruction)
1158111591{
11582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11583 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11584 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11586 out_val->data.x_maybe = nullptr;
11592 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
11593 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11594 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11595 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11596 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11597 out_val->data.x_maybe = nullptr;
11598 return nullable_type;
11599 }
11600 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11601 instruction->base.source_node, instruction->nullable);
11602 ir_link_new_instruction(new_instruction, &instruction->base);
1158711603 return nullable_type;
11604 } else {
11605 assert(ira->codegen->have_err_ret_tracing);
11606 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11607 instruction->base.source_node, instruction->nullable);
11608 ir_link_new_instruction(new_instruction, &instruction->base);
11609 return get_ptr_to_stack_trace_type(ira->codegen);
1158811610 }
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;
1159411611}
1159511612
1159611613static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
......@@ -17904,6 +17921,34 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
1790417921 return out_val->type;
1790517922}
1790617923
17924static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
17925 IrInstructionMergeErrRetTraces *instruction)
17926{
17927 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other;
17928 if (type_is_invalid(coro_promise_ptr->value.type))
17929 return ira->codegen->builtin_types.entry_invalid;
17930
17931 assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer);
17932 TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
17933 assert(promise_frame_type->id == TypeTableEntryIdStruct);
17934 TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
17935
17936 if (!type_can_fail(promise_result_type)) {
17937 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17938 out_val->type = ira->codegen->builtin_types.entry_void;
17939 return out_val->type;
17940 }
17941
17942 TypeStructField *field = find_struct_type_field(promise_frame_type, buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME));
17943 assert(field != nullptr);
17944
17945 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
17946 instruction->base.source_node, coro_promise_ptr, field);
17947 ir_link_new_instruction(result, &instruction->base);
17948 result->value.type = ira->codegen->builtin_types.entry_void;
17949 return result->value.type;
17950}
17951
1790717952static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
1790817953 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
1790917954 instruction->base.source_node);
......@@ -18155,6 +18200,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1815518200 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
1815618201 case IrInstructionIdAddImplicitReturnType:
1815718202 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
18203 case IrInstructionIdMergeErrRetTraces:
18204 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
1815818205 }
1815918206 zig_unreachable();
1816018207}
......@@ -18282,6 +18329,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1828218329 case IrInstructionIdAwaitBookkeeping:
1828318330 case IrInstructionIdSaveErrRetAddr:
1828418331 case IrInstructionIdAddImplicitReturnType:
18332 case IrInstructionIdMergeErrRetTraces:
1828518333 return true;
1828618334
1828718335 case IrInstructionIdPhi:
src/ir_print.cpp+23-1
......@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
10241024}
10251025
10261026static 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, ")");
10281037}
10291038
10301039static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
......@@ -1179,6 +1188,16 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
11791188 fprintf(irp->f, ")");
11801189}
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 if (instruction->resolved_field != nullptr) {
1196 fprintf(irp->f, "field '%s'", buf_ptr(instruction->resolved_field->name));
1197 }
1198 fprintf(irp->f, ")");
1199}
1200
11821201static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11831202 ir_print_prefix(irp, instruction);
11841203 switch (instruction->id) {
......@@ -1559,6 +1578,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15591578 case IrInstructionIdAddImplicitReturnType:
15601579 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
15611580 break;
1581 case IrInstructionIdMergeErrRetTraces:
1582 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
1583 break;
15621584 }
15631585 fprintf(irp->f, "\n");
15641586}