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 {
20342034 IrInstructionIdAtomicRmw,
20352035 IrInstructionIdPromiseResultType,
20362036 IrInstructionIdAwaitBookkeeping,
2037 IrInstructionIdSaveErrRetAddr,
20372038};
20382039
20392040struct IrInstruction {
......@@ -2988,6 +2989,10 @@ struct IrInstructionAwaitBookkeeping {
29882989 IrInstruction *promise_result_type;
29892990};
29902991
2992struct IrInstructionSaveErrRetAddr {
2993 IrInstruction base;
2994};
2995
29912996static const size_t slice_ptr_index = 0;
29922997static 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) {
16071607 return instruction->llvm_value;
16081608}
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
16101625static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
16111626 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
16121627 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 }
16361629 if (handle_is_ptr(return_type)) {
16371630 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
16381631 assert(g->cur_ret_ptr);
......@@ -4400,6 +4393,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
44004393 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
44014394 case IrInstructionIdAtomicRmw:
44024395 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4396 case IrInstructionIdSaveErrRetAddr:
4397 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
44034398 }
44044399 zig_unreachable();
44054400}
src/ir.cpp+62-24
......@@ -713,6 +713,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
713713 return IrInstructionIdAwaitBookkeeping;
714714}
715715
716static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
717 return IrInstructionIdSaveErrRetAddr;
718}
719
716720template<typename T>
717721static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
718722 T *special_instruction = allocate<T>(1);
......@@ -2678,6 +2682,11 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
26782682 return &instruction->base;
26792683}
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
26812690static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
26822691 results[ReturnKindUnconditional] = 0;
26832692 results[ReturnKindError] = 0;
......@@ -2750,16 +2759,16 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
27502759 return nullptr;
27512760}
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
27532767static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
27542768 bool is_generated_code)
27552769{
2756 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
2757 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2770 bool is_async = exec_is_async(irb->exec);
27582771 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 //}
27632772 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
27642773 return_inst->is_gen = is_generated_code;
27652774 return return_inst;
......@@ -2781,21 +2790,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
27812790 // the above blocks are rendered by ir_gen after the rest of codegen
27822791}
27832792
2784//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {
2785// if (!irb->codegen->have_err_ret_tracing)
2786// return;
2787//
2788// if (is_async) {
2789// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2790// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);
2791// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2792// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2793// return;
2794// }
2795//
2796// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2797// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2798//}
2793static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2794 if (!g->have_err_ret_tracing)
2795 return false;
2796 FnTableEntry *fn_entry = exec_fn_entry(exec);
2797 if (fn_entry == nullptr)
2798 return false;
2799 if (exec->is_inline)
2800 return false;
2801 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2802}
2803
2804static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2805 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2806 return;
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
28002821static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
28012822 assert(node->type == NodeTypeReturnExpr);
......@@ -2856,7 +2877,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28562877 if (have_err_defers) {
28572878 ir_gen_defers_for_block(irb, scope, outer_scope, true);
28582879 }
2859 //ir_gen_save_err_ret_addr(irb, scope, node, is_async);
2880 ir_gen_save_err_ret_addr(irb, scope, node);
28602881 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28612882
28622883 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,
28952916 ir_set_cursor_at_end_and_append_block(irb, return_block);
28962917 ir_gen_defers_for_block(irb, scope, outer_scope, true);
28972918 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2919 ir_gen_save_err_ret_addr(irb, scope, node);
28982920 ir_gen_async_return(irb, scope, node, err_val, false);
28992921
29002922 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
64066428 return false;
64076429
64086430 if (!instr_is_unreachable(result)) {
6431 // no need for save_err_ret_addr because this cannot return error
64096432 ir_gen_async_return(irb, scope, result->source_node, result, true);
64106433 }
64116434
......@@ -11464,13 +11487,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1146411487 return ira->codegen->builtin_types.entry_void;
1146511488}
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
1146711495static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1146811496 IrInstructionErrorReturnTrace *instruction)
1146911497{
11470 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
1147111498 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
1147211499 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)) {
1147411501 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1147511502 out_val->data.x_maybe = nullptr;
1147611503 return nullable_type;
......@@ -17775,6 +17802,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
1777517802 return out_val->type;
1777617803}
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
1777817813static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1777917814 switch (instruction->id) {
1778017815 case IrInstructionIdInvalid:
......@@ -18012,6 +18047,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1801218047 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1801318048 case IrInstructionIdAwaitBookkeeping:
1801418049 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
18050 case IrInstructionIdSaveErrRetAddr:
18051 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
1801518052 }
1801618053 zig_unreachable();
1801718054}
......@@ -18137,6 +18174,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1813718174 case IrInstructionIdCoroSave:
1813818175 case IrInstructionIdCoroAllocHelper:
1813918176 case IrInstructionIdAwaitBookkeeping:
18177 case IrInstructionIdSaveErrRetAddr:
1814018178 return true;
1814118179
1814218180 case IrInstructionIdPhi:
src/ir_print.cpp+7
......@@ -1161,6 +1161,10 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
11611161 fprintf(irp->f, ")");
11621162}
11631163
1164static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1165 fprintf(irp->f, "@saveErrRetAddr()");
1166}
1167
11641168static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11651169 ir_print_prefix(irp, instruction);
11661170 switch (instruction->id) {
......@@ -1532,6 +1536,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15321536 case IrInstructionIdAwaitBookkeeping:
15331537 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
15341538 break;
1539 case IrInstructionIdSaveErrRetAddr:
1540 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
1541 break;
15351542 }
15361543 fprintf(irp->f, "\n");
15371544}