mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 12:33:19 +00:00
parent
2cff31937f
commit
b1c07c0ea9
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
86
src/ir.cpp
86
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:
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user