stage2: properly reset error return trace index

This commit is contained in:
Veikka Tuominen 2022-09-12 20:41:25 +03:00 committed by Cody Tapscott
parent 28054d96f0
commit 5316a00a18
4 changed files with 111 additions and 5 deletions

View file

@ -2471,6 +2471,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.try_ptr,
//.try_inline,
//.try_ptr_inline,
.save_err_ret_index,
=> break :b false,
.extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) {
@ -2533,6 +2534,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.validate_array_init_ty,
.validate_struct_init_ty,
.validate_deref,
.restore_err_ret_index,
=> break :b true,
.@"defer" => unreachable,
@ -5152,10 +5154,16 @@ fn orelseCatchExpr(
const astgen = parent_gz.astgen;
const tree = astgen.tree;
const do_err_trace = astgen.fn_block != null and (cond_op == .is_non_err or cond_op == .is_non_err_ptr);
var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.unstack();
if (do_err_trace) {
block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node);
}
const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
.ref => .ref,
else => .none,
@ -5220,7 +5228,7 @@ fn orelseCatchExpr(
// instructions or not.
const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break";
return finishThenElseBlock(
const result = try finishThenElseBlock(
parent_gz,
rl,
node,
@ -5235,6 +5243,16 @@ fn orelseCatchExpr(
block,
break_tag,
);
if (do_err_trace) {
_ = try parent_gz.add(.{
.tag = .restore_err_ret_index,
.data = .{ .un_node = .{
.operand = parent_gz.saved_err_trace_index,
.src_node = parent_gz.nodeIndexToRelative(node),
} },
});
}
return result;
}
/// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`.
@ -5430,10 +5448,16 @@ fn ifExpr(
const tree = astgen.tree;
const token_tags = tree.tokens.items(.tag);
const do_err_trace = astgen.fn_block != null and if_full.error_token != null;
var block_scope = parent_gz.makeSubBlock(scope);
block_scope.setBreakResultLoc(rl);
defer block_scope.unstack();
if (do_err_trace) {
block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node);
}
const payload_is_ref = if (if_full.payload_token) |payload_token|
token_tags[payload_token] == .asterisk
else
@ -5602,7 +5626,7 @@ fn ifExpr(
};
const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break";
return finishThenElseBlock(
const result = try finishThenElseBlock(
parent_gz,
rl,
node,
@ -5617,6 +5641,16 @@ fn ifExpr(
block,
break_tag,
);
if (do_err_trace) {
_ = try parent_gz.add(.{
.tag = .restore_err_ret_index,
.data = .{ .un_node = .{
.operand = parent_gz.saved_err_trace_index,
.src_node = parent_gz.nodeIndexToRelative(node),
} },
});
}
return result;
}
/// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
@ -10300,6 +10334,8 @@ const GenZir = struct {
/// Keys are the raw instruction index, values are the closure_capture instruction.
captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
saved_err_trace_index: Zir.Inst.Ref = .none,
const unstacked_top = std.math.maxInt(usize);
/// Call unstack before adding any new instructions to containing GenZir.
fn unstack(self: *GenZir) void {
@ -10344,6 +10380,7 @@ const GenZir = struct {
.any_defer_node = gz.any_defer_node,
.instructions = gz.instructions,
.instructions_top = gz.instructions.items.len,
.saved_err_trace_index = gz.saved_err_trace_index,
};
}

View file

@ -926,6 +926,8 @@ fn analyzeBodyInner(
.ret_ptr => try sema.zirRetPtr(block, inst),
.ret_type => try sema.addType(sema.fn_ret_ty),
.save_err_ret_index => try sema.zirSaveErrRetIndex(block, inst),
// Instructions that we know to *always* be noreturn based solely on their tag.
// These functions match the return type of analyzeBody so that we can
// tail call them here.
@ -1208,6 +1210,11 @@ fn analyzeBodyInner(
i += 1;
continue;
},
.restore_err_ret_index => {
try sema.zirRestoreErrRetIndex(block, inst);
i += 1;
continue;
},
// Special case instructions to handle comptime control flow.
.@"break" => {
@ -16176,6 +16183,52 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
backend_supports_error_return_tracing;
}
fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].node;
const src = LazySrcLoc.nodeOffset(inst_data);
// This is only relevant at runtime.
if (block.is_comptime) return Air.Inst.Ref.zero_usize;
const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
sema.mod.comp.bin_file.options.error_return_tracing and
backend_supports_error_return_tracing;
if (!ok) return Air.Inst.Ref.zero_usize;
const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
return sema.fieldVal(block, src, err_return_trace, "index", src);
}
fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
// This is only relevant at runtime.
if (block.is_comptime) return;
const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
sema.mod.comp.bin_file.options.error_return_tracing and
backend_supports_error_return_tracing;
if (!ok) return;
const operand = if (inst_data.operand != .none)
try sema.resolveInst(inst_data.operand)
else
.zero_usize;
const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true);
try sema.storePtr2(block, src, field_ptr, src, operand, src, .store);
}
fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
@ -17181,8 +17234,6 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
_ = src;
const operand = try sema.resolveInst(inst_data.operand);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };

View file

@ -988,6 +988,15 @@ pub const Inst = struct {
/// Uses the `err_defer_code` union field.
defer_err_code,
/// Saves the current error return case if it exists,
/// otherwise just returns zero.
/// Uses the `node` union field.
save_err_ret_index,
/// Sets error return trace to zero if no operand is given,
/// otherwise sets the value to the given amount.
/// Uses the `un_node` union field.
restore_err_ret_index,
/// The ZIR instruction tag is one of the `Extended` ones.
/// Uses the `extended` union field.
extended,
@ -1236,6 +1245,8 @@ pub const Inst = struct {
//.try_ptr_inline,
.@"defer",
.defer_err_code,
.save_err_ret_index,
.restore_err_ret_index,
=> false,
.@"break",
@ -1305,6 +1316,7 @@ pub const Inst = struct {
.check_comptime_control_flow,
.@"defer",
.defer_err_code,
.restore_err_ret_index,
=> true,
.param,
@ -1530,6 +1542,7 @@ pub const Inst = struct {
.try_ptr,
//.try_inline,
//.try_ptr_inline,
.save_err_ret_index,
=> false,
.extended => switch (data.extended.opcode) {
@ -1810,6 +1823,9 @@ pub const Inst = struct {
.@"defer" = .@"defer",
.defer_err_code = .defer_err_code,
.save_err_ret_index = .node,
.restore_err_ret_index = .un_node,
.extended = .extended,
});
};

View file

@ -232,6 +232,7 @@ const Writer = struct {
.validate_deref,
.overflow_arithmetic_ptr,
.check_comptime_control_flow,
.restore_err_ret_index,
=> try self.writeUnNode(stream, inst),
.ref,
@ -405,6 +406,7 @@ const Writer = struct {
.alloc_inferred_comptime_mut,
.ret_ptr,
.ret_type,
.save_err_ret_index,
=> try self.writeNode(stream, inst),
.error_value,
@ -440,7 +442,7 @@ const Writer = struct {
.dbg_block_begin,
.dbg_block_end,
=> try stream.writeAll("))"),
=> try stream.writeAll(")"),
.closure_get => try self.writeInstNode(stream, inst),