ERR/E3.0 (slice 3b): comptime trace resolution

#run failures now print the same `func at file:line:col` trace as
runtime, resolved in-process via the interpreter's IR/source tables.

- Read-side context-split op `.trace_resolve` (mirror of .trace_frame),
  lowered from a name-recognized `__trace_resolve_frame(u64) -> Frame`.
- emit_llvm: inttoptr the operand to *Frame + load (the value
  .trace_frame stamped in).
- interp: unpack (func_id << 32 | span.start); resolve func/file from
  module.functions and line/col via SourceLoc.compute over a new
  source_map (setSourceMap wired at every production interp site).
- trace.sx: frame_at -> u64; to_string routes each frame through
  __trace_resolve_frame, so one source works in both machines.

Compiled path behavior unchanged (243/244/247 identical; it now loads
via the op). New examples/253-comptime-trace.sx exercises the comptime
path. Gates: zig build, zig build test, run_examples.sh -> 291 passed.
This commit is contained in:
agra
2026-06-01 15:33:50 +03:00
parent 11f6377d9c
commit b5241243e6
11 changed files with 120 additions and 5 deletions

View File

@@ -1347,6 +1347,7 @@ pub const LLVMEmitter = struct {
const func_id = ir_inst.FuncId.fromIndex(@intCast(i));
var interp_inst = Interpreter.init(self.ir_mod, self.alloc);
interp_inst.build_config = &self.build_config;
if (self.import_sources) |sm| interp_inst.setSourceMap(sm);
_ = interp_inst.call(func_id, &.{}) catch {};
// Route #run `print` output to fd 1 so it joins the
// JIT-executed runtime's stream. Same call site shape as
@@ -1385,6 +1386,7 @@ pub const LLVMEmitter = struct {
if (global.comptime_func) |func_id| {
var interp_inst = Interpreter.init(self.ir_mod, self.alloc);
interp_inst.build_config = &self.build_config;
if (self.import_sources) |sm| interp_inst.setSourceMap(sm);
Interpreter.last_bail_op = null;
Interpreter.last_bail_builtin = null;
Interpreter.last_bail_detail = null;
@@ -1896,6 +1898,14 @@ pub const LLVMEmitter = struct {
.trace_frame => {
self.mapRef(self.emitTraceFrame(instruction));
},
.trace_resolve => |u| {
// The operand is a `Frame*` stamped in by `.trace_frame` (as
// i64); reinterpret and load it.
const raw = self.resolveRef(u.operand);
const frame_ty = self.getFrameStructType();
const ptr = c.LLVMBuildIntToPtr(self.builder, raw, self.cached_ptr, "frame.ptr");
self.mapRef(c.LLVMBuildLoad2(self.builder, frame_ty, ptr, "frame.val"));
},
.const_string => |str_id| {
const str = self.ir_mod.types.getString(str_id);
const llvm_val = self.emitStringConstant(str);
@@ -2517,6 +2527,7 @@ pub const LLVMEmitter = struct {
if (callee_func.is_comptime and call_op.args.len == 0) {
var interp_inst = Interpreter.init(self.ir_mod, self.alloc);
interp_inst.build_config = &self.build_config;
if (self.import_sources) |sm| interp_inst.setSourceMap(sm);
defer interp_inst.deinit();
if (interp_inst.call(call_op.callee, &.{})) |result| {
if (result.asInt()) |v| {