authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-12 23:03:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-24 18:28:32-04:00
logb1c07c0ea9e351a43c9bc2fe747fc07c0a19e005
tree776d95a9b65f0cf2391bf553e536dbc2f200b127
parent2cff31937f6008769ad1034f9451d136d03c06bb

move error ret tracing codegen to zig ir

progress towards #821

4 files changed, 91 insertions(+), 46 deletions(-)

src/all_types.hpp+5
...@@ -2034,6 +2034,7 @@ enum IrInstructionId {...@@ -2034,6 +2034,7 @@ enum IrInstructionId {
2034 IrInstructionIdAtomicRmw,2034 IrInstructionIdAtomicRmw,
2035 IrInstructionIdPromiseResultType,2035 IrInstructionIdPromiseResultType,
2036 IrInstructionIdAwaitBookkeeping,2036 IrInstructionIdAwaitBookkeeping,
2037 IrInstructionIdSaveErrRetAddr,
2037};2038};
20382039
2039struct IrInstruction {2040struct IrInstruction {
...@@ -2988,6 +2989,10 @@ struct IrInstructionAwaitBookkeeping {...@@ -2988,6 +2989,10 @@ struct IrInstructionAwaitBookkeeping {
2988 IrInstruction *promise_result_type;2989 IrInstruction *promise_result_type;
2989};2990};
29902991
2992struct IrInstructionSaveErrRetAddr {
2993 IrInstruction base;
2994};
2995
2991static const size_t slice_ptr_index = 0;2996static const size_t slice_ptr_index = 0;
2992static const size_t slice_len_index = 1;2997static const size_t slice_len_index = 1;
29932998
src/codegen.cpp+17-22
...@@ -1607,32 +1607,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1607,32 +1607,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1607 return instruction->llvm_value;1607 return instruction->llvm_value;
1608}1608}
16091609
1610static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
1611 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
1612{
1613 assert(g->have_err_ret_tracing);
1614
1615 LLVMValueRef return_err_fn = get_return_err_fn(g);
1616 LLVMValueRef args[] = {
1617 g->cur_err_ret_trace_val,
1618 };
1619 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1620 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1621 LLVMSetTailCall(call_instruction, true);
1622 return call_instruction;
1623}
1624
1610static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1625static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1611 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1626 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1612 TypeTableEntry *return_type = return_instruction->value->value.type;1627 TypeTableEntry *return_type = return_instruction->value->value.type;
16131628
1614 if (g->have_err_ret_tracing) {
1615 bool is_err_return = false;
1616 if (return_type->id == TypeTableEntryIdErrorUnion) {
1617 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1618 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1619 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1620 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1621 // TODO: emit a branch to check if the return value is an error
1622 }
1623 } else if (return_type->id == TypeTableEntryIdErrorSet) {
1624 is_err_return = true;
1625 }
1626 if (is_err_return) {
1627 LLVMValueRef return_err_fn = get_return_err_fn(g);
1628 LLVMValueRef args[] = {
1629 g->cur_err_ret_trace_val,
1630 };
1631 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1632 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1633 LLVMSetTailCall(call_instruction, true);
1634 }
1635 }
1636 if (handle_is_ptr(return_type)) {1629 if (handle_is_ptr(return_type)) {
1637 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1630 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1638 assert(g->cur_ret_ptr);1631 assert(g->cur_ret_ptr);
...@@ -4400,6 +4393,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4400,6 +4393,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4400 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);4393 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4401 case IrInstructionIdAtomicRmw:4394 case IrInstructionIdAtomicRmw:
4402 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);4395 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4396 case IrInstructionIdSaveErrRetAddr:
4397 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4403 }4398 }
4404 zig_unreachable();4399 zig_unreachable();
4405}4400}
src/ir.cpp+62-24
...@@ -713,6 +713,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping...@@ -713,6 +713,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
713 return IrInstructionIdAwaitBookkeeping;713 return IrInstructionIdAwaitBookkeeping;
714}714}
715715
716static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
717 return IrInstructionIdSaveErrRetAddr;
718}
719
716template<typename T>720template<typename T>
717static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {721static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
718 T *special_instruction = allocate<T>(1);722 T *special_instruction = allocate<T>(1);
...@@ -2678,6 +2682,11 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A...@@ -2678,6 +2682,11 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
2678 return &instruction->base;2682 return &instruction->base;
2679}2683}
26802684
2685static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2686 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
2687 return &instruction->base;
2688}
2689
2681static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2690static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2682 results[ReturnKindUnconditional] = 0;2691 results[ReturnKindUnconditional] = 0;
2683 results[ReturnKindError] = 0;2692 results[ReturnKindError] = 0;
...@@ -2750,16 +2759,16 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -2750,16 +2759,16 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
2750 return nullptr;2759 return nullptr;
2751}2760}
27522761
2762static bool exec_is_async(IrExecutable *exec) {
2763 FnTableEntry *fn_entry = exec_fn_entry(exec);
2764 return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2765}
2766
2753static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,2767static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
2754 bool is_generated_code)2768 bool is_generated_code)
2755{2769{
2756 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);2770 bool is_async = exec_is_async(irb->exec);
2757 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2758 if (!is_async) {2771 if (!is_async) {
2759 //if (irb->codegen->have_err_ret_tracing) {
2760 // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2761 // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2762 //}
2763 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);2772 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
2764 return_inst->is_gen = is_generated_code;2773 return_inst->is_gen = is_generated_code;
2765 return return_inst;2774 return return_inst;
...@@ -2781,21 +2790,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2781,21 +2790,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2781 // the above blocks are rendered by ir_gen after the rest of codegen2790 // the above blocks are rendered by ir_gen after the rest of codegen
2782}2791}
27832792
2784//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {2793static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2785// if (!irb->codegen->have_err_ret_tracing)2794 if (!g->have_err_ret_tracing)
2786// return;2795 return false;
2787//2796 FnTableEntry *fn_entry = exec_fn_entry(exec);
2788// if (is_async) {2797 if (fn_entry == nullptr)
2789// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);2798 return false;
2790// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);2799 if (exec->is_inline)
2791// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);2800 return false;
2792// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);2801 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2793// return;2802}
2794// }2803
2795//2804static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2796// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);2805 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2797// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);2806 return;
2798//}2807
2808 bool is_async = exec_is_async(irb->exec);
2809
2810 if (is_async) {
2811 //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2812 //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
2813 //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2814 //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2815 return;
2816 }
2817
2818 ir_build_save_err_ret_addr(irb, scope, node);
2819}
27992820
2800static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2821static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2801 assert(node->type == NodeTypeReturnExpr);2822 assert(node->type == NodeTypeReturnExpr);
...@@ -2856,7 +2877,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2856,7 +2877,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2856 if (have_err_defers) {2877 if (have_err_defers) {
2857 ir_gen_defers_for_block(irb, scope, outer_scope, true);2878 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2858 }2879 }
2859 //ir_gen_save_err_ret_addr(irb, scope, node, is_async);2880 ir_gen_save_err_ret_addr(irb, scope, node);
2860 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2881 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28612882
2862 ir_set_cursor_at_end_and_append_block(irb, ok_block);2883 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -2895,6 +2916,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2895,6 +2916,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2895 ir_set_cursor_at_end_and_append_block(irb, return_block);2916 ir_set_cursor_at_end_and_append_block(irb, return_block);
2896 ir_gen_defers_for_block(irb, scope, outer_scope, true);2917 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2897 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2918 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2919 ir_gen_save_err_ret_addr(irb, scope, node);
2898 ir_gen_async_return(irb, scope, node, err_val, false);2920 ir_gen_async_return(irb, scope, node, err_val, false);
28992921
2900 ir_set_cursor_at_end_and_append_block(irb, continue_block);2922 ir_set_cursor_at_end_and_append_block(irb, continue_block);
...@@ -6406,6 +6428,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6406,6 +6428,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6406 return false;6428 return false;
64076429
6408 if (!instr_is_unreachable(result)) {6430 if (!instr_is_unreachable(result)) {
6431 // no need for save_err_ret_addr because this cannot return error
6409 ir_gen_async_return(irb, scope, result->source_node, result, true);6432 ir_gen_async_return(irb, scope, result->source_node, result, true);
6410 }6433 }
64116434
...@@ -11464,13 +11487,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -11464,13 +11487,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
11464 return ira->codegen->builtin_types.entry_void;11487 return ira->codegen->builtin_types.entry_void;
11465}11488}
1146611489
11490static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
11491 FnTableEntry *fn_entry = exec_fn_entry(exec);
11492 return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing;
11493}
11494
11467static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11495static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11468 IrInstructionErrorReturnTrace *instruction)11496 IrInstructionErrorReturnTrace *instruction)
11469{11497{
11470 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
11471 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11498 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11472 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11499 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11473 if (fn_entry == nullptr || !fn_entry->calls_or_awaits_errorable_fn || !ira->codegen->have_err_ret_tracing) {11500 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11474 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11501 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11475 out_val->data.x_maybe = nullptr;11502 out_val->data.x_maybe = nullptr;
11476 return nullable_type;11503 return nullable_type;
...@@ -17775,6 +17802,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17775,6 +17802,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17775 return out_val->type;17802 return out_val->type;
17776}17803}
1777717804
17805static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
17806 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
17807 instruction->base.source_node);
17808 ir_link_new_instruction(result, &instruction->base);
17809 result->value.type = ira->codegen->builtin_types.entry_void;
17810 return result->value.type;
17811}
17812
17778static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {17813static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17779 switch (instruction->id) {17814 switch (instruction->id) {
17780 case IrInstructionIdInvalid:17815 case IrInstructionIdInvalid:
...@@ -18012,6 +18047,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18012,6 +18047,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18012 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);18047 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
18013 case IrInstructionIdAwaitBookkeeping:18048 case IrInstructionIdAwaitBookkeeping:
18014 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);18049 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
18050 case IrInstructionIdSaveErrRetAddr:
18051 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
18015 }18052 }
18016 zig_unreachable();18053 zig_unreachable();
18017}18054}
...@@ -18137,6 +18174,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18137,6 +18174,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18137 case IrInstructionIdCoroSave:18174 case IrInstructionIdCoroSave:
18138 case IrInstructionIdCoroAllocHelper:18175 case IrInstructionIdCoroAllocHelper:
18139 case IrInstructionIdAwaitBookkeeping:18176 case IrInstructionIdAwaitBookkeeping:
18177 case IrInstructionIdSaveErrRetAddr:
18140 return true;18178 return true;
1814118179
18142 case IrInstructionIdPhi:18180 case IrInstructionIdPhi:
src/ir_print.cpp+7
...@@ -1161,6 +1161,10 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi...@@ -1161,6 +1161,10 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
1161 fprintf(irp->f, ")");1161 fprintf(irp->f, ")");
1162}1162}
11631163
1164static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1165 fprintf(irp->f, "@saveErrRetAddr()");
1166}
1167
1164static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1168static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1165 ir_print_prefix(irp, instruction);1169 ir_print_prefix(irp, instruction);
1166 switch (instruction->id) {1170 switch (instruction->id) {
...@@ -1532,6 +1536,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1532,6 +1536,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1532 case IrInstructionIdAwaitBookkeeping:1536 case IrInstructionIdAwaitBookkeeping:
1533 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);1537 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
1534 break;1538 break;
1539 case IrInstructionIdSaveErrRetAddr:
1540 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
1541 break;
1535 }1542 }
1536 fprintf(irp->f, "\n");1543 fprintf(irp->f, "\n");
1537}1544}