Commit b1c07c0ea9
Changed files (4)
src/all_types.hpp
@@ -2034,6 +2034,7 @@ enum IrInstructionId {
IrInstructionIdAtomicRmw,
IrInstructionIdPromiseResultType,
IrInstructionIdAwaitBookkeeping,
+ IrInstructionIdSaveErrRetAddr,
};
struct IrInstruction {
@@ -2988,6 +2989,10 @@ struct IrInstructionAwaitBookkeeping {
IrInstruction *promise_result_type;
};
+struct IrInstructionSaveErrRetAddr {
+ IrInstruction base;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
src/codegen.cpp
@@ -1607,32 +1607,25 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
return instruction->llvm_value;
}
+static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
+ IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
+{
+ assert(g->have_err_ret_tracing);
+
+ LLVMValueRef return_err_fn = get_return_err_fn(g);
+ LLVMValueRef args[] = {
+ g->cur_err_ret_trace_val,
+ };
+ LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
+ get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
+ LLVMSetTailCall(call_instruction, true);
+ return call_instruction;
+}
+
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
TypeTableEntry *return_type = return_instruction->value->value.type;
- if (g->have_err_ret_tracing) {
- bool is_err_return = false;
- if (return_type->id == TypeTableEntryIdErrorUnion) {
- if (return_instruction->value->value.special == ConstValSpecialStatic) {
- is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
- } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
- is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
- // TODO: emit a branch to check if the return value is an error
- }
- } else if (return_type->id == TypeTableEntryIdErrorSet) {
- is_err_return = true;
- }
- if (is_err_return) {
- LLVMValueRef return_err_fn = get_return_err_fn(g);
- LLVMValueRef args[] = {
- g->cur_err_ret_trace_val,
- };
- LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
- get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
- LLVMSetTailCall(call_instruction, true);
- }
- }
if (handle_is_ptr(return_type)) {
if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
assert(g->cur_ret_ptr);
@@ -4400,6 +4393,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
case IrInstructionIdAtomicRmw:
return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
+ case IrInstructionIdSaveErrRetAddr:
+ return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
}
zig_unreachable();
}
src/ir.cpp
@@ -713,6 +713,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping
return IrInstructionIdAwaitBookkeeping;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
+ return IrInstructionIdSaveErrRetAddr;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -2678,6 +2682,11 @@ static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, A
return &instruction->base;
}
+static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+ IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -2750,16 +2759,16 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
return nullptr;
}
+static bool exec_is_async(IrExecutable *exec) {
+ FnTableEntry *fn_entry = exec_fn_entry(exec);
+ return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
+}
+
static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
bool is_generated_code)
{
- FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
- bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
+ bool is_async = exec_is_async(irb->exec);
if (!is_async) {
- //if (irb->codegen->have_err_ret_tracing) {
- // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
- // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
- //}
IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
return_inst->is_gen = is_generated_code;
return return_inst;
@@ -2781,21 +2790,33 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
// the above blocks are rendered by ir_gen after the rest of codegen
}
-//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {
-// if (!irb->codegen->have_err_ret_tracing)
-// return;
-//
-// if (is_async) {
-// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
-// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);
-// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
-// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
-// return;
-// }
-//
-// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
-// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
-//}
+static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
+ if (!g->have_err_ret_tracing)
+ return false;
+ FnTableEntry *fn_entry = exec_fn_entry(exec);
+ if (fn_entry == nullptr)
+ return false;
+ if (exec->is_inline)
+ return false;
+ return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
+}
+
+static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
+ if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
+ return;
+
+ bool is_async = exec_is_async(irb->exec);
+
+ if (is_async) {
+ //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
+ //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
+ //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
+ //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
+ return;
+ }
+
+ ir_build_save_err_ret_addr(irb, scope, node);
+}
static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
assert(node->type == NodeTypeReturnExpr);
@@ -2856,7 +2877,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
if (have_err_defers) {
ir_gen_defers_for_block(irb, scope, outer_scope, true);
}
- //ir_gen_save_err_ret_addr(irb, scope, node, is_async);
+ ir_gen_save_err_ret_addr(irb, scope, node);
ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
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,
ir_set_cursor_at_end_and_append_block(irb, return_block);
ir_gen_defers_for_block(irb, scope, outer_scope, true);
IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
+ ir_gen_save_err_ret_addr(irb, scope, node);
ir_gen_async_return(irb, scope, node, err_val, false);
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
return false;
if (!instr_is_unreachable(result)) {
+ // no need for save_err_ret_addr because this cannot return error
ir_gen_async_return(irb, scope, result->source_node, result, true);
}
@@ -11464,13 +11487,17 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
return ira->codegen->builtin_types.entry_void;
}
+static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
+ FnTableEntry *fn_entry = exec_fn_entry(exec);
+ return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing;
+}
+
static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
IrInstructionErrorReturnTrace *instruction)
{
- FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
- if (fn_entry == nullptr || !fn_entry->calls_or_awaits_errorable_fn || !ira->codegen->have_err_ret_tracing) {
+ if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_maybe = nullptr;
return nullable_type;
@@ -17775,6 +17802,14 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
return out_val->type;
}
+static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
+ IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node);
+ ir_link_new_instruction(result, &instruction->base);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result->value.type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -18012,6 +18047,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
case IrInstructionIdAwaitBookkeeping:
return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
+ case IrInstructionIdSaveErrRetAddr:
+ return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
}
zig_unreachable();
}
@@ -18137,6 +18174,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCoroSave:
case IrInstructionIdCoroAllocHelper:
case IrInstructionIdAwaitBookkeeping:
+ case IrInstructionIdSaveErrRetAddr:
return true;
case IrInstructionIdPhi:
src/ir_print.cpp
@@ -1161,6 +1161,10 @@ static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeepi
fprintf(irp->f, ")");
}
+static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
+ fprintf(irp->f, "@saveErrRetAddr()");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1532,6 +1536,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAwaitBookkeeping:
ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
break;
+ case IrInstructionIdSaveErrRetAddr:
+ ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}