mirror of
https://github.com/ziglang/zig.git
synced 2026-02-17 06:49:23 +00:00
stage2: preliminary reworking for whole-file-AstGen
See #8516. * AstGen is now done on whole files at once rather than per Decl. * Introduce a new wait group for AstGen tasks. `performAllTheWork` waits for all AstGen tasks to be complete before doing Sema, single-threaded. - The C object compilation tasks are moved to be spawned after AstGen, since they only need to complete by the end of the function. With this commit, the codebase compiles, but much more reworking is needed to get things back into a useful state.
This commit is contained in:
parent
9088d40e83
commit
3114115348
1118
BRANCH_TODO
1118
BRANCH_TODO
File diff suppressed because it is too large
Load Diff
1665
src/AstGen.zig
1665
src/AstGen.zig
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,11 @@ work_queue: std.fifo.LinearFifo(Job, .Dynamic),
|
||||
/// gets linked with the Compilation.
|
||||
c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
|
||||
|
||||
/// These jobs are to tokenize, parse, and astgen files, which may be outdated
|
||||
/// since the last compilation, as well as scan for `@import` and queue up
|
||||
/// additional jobs corresponding to those new files.
|
||||
astgen_work_queue: std.fifo.LinearFifo(*Module.Scope.File, .Dynamic),
|
||||
|
||||
/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
|
||||
/// This data is accessed by multiple threads and is protected by `mutex`.
|
||||
failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
|
||||
@ -141,6 +146,7 @@ emit_analysis: ?EmitLoc,
|
||||
emit_docs: ?EmitLoc,
|
||||
|
||||
work_queue_wait_group: WaitGroup,
|
||||
astgen_wait_group: WaitGroup,
|
||||
|
||||
pub const InnerError = Module.InnerError;
|
||||
|
||||
@ -1210,6 +1216,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
.emit_docs = options.emit_docs,
|
||||
.work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
|
||||
.c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
|
||||
.astgen_work_queue = std.fifo.LinearFifo(*Module.Scope.File, .Dynamic).init(gpa),
|
||||
.keep_source_files_loaded = options.keep_source_files_loaded,
|
||||
.use_clang = use_clang,
|
||||
.clang_argv = options.clang_argv,
|
||||
@ -1238,6 +1245,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
.test_evented_io = options.test_evented_io,
|
||||
.debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
|
||||
.work_queue_wait_group = undefined,
|
||||
.astgen_wait_group = undefined,
|
||||
};
|
||||
break :comp comp;
|
||||
};
|
||||
@ -1246,6 +1254,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
try comp.work_queue_wait_group.init();
|
||||
errdefer comp.work_queue_wait_group.deinit();
|
||||
|
||||
try comp.astgen_wait_group.init();
|
||||
errdefer comp.astgen_wait_group.deinit();
|
||||
|
||||
if (comp.bin_file.options.module) |mod| {
|
||||
try comp.work_queue.writeItem(.{ .generate_builtin_zig = {} });
|
||||
}
|
||||
@ -1381,6 +1392,7 @@ pub fn destroy(self: *Compilation) void {
|
||||
const gpa = self.gpa;
|
||||
self.work_queue.deinit();
|
||||
self.c_object_work_queue.deinit();
|
||||
self.astgen_work_queue.deinit();
|
||||
|
||||
{
|
||||
var it = self.crt_files.iterator();
|
||||
@ -1431,6 +1443,7 @@ pub fn destroy(self: *Compilation) void {
|
||||
if (self.owned_link_dir) |*dir| dir.close();
|
||||
|
||||
self.work_queue_wait_group.deinit();
|
||||
self.astgen_wait_group.deinit();
|
||||
|
||||
// This destroys `self`.
|
||||
self.arena_state.promote(gpa).deinit();
|
||||
@ -1470,42 +1483,17 @@ pub fn update(self: *Compilation) !void {
|
||||
module.compile_log_text.shrinkAndFree(module.gpa, 0);
|
||||
module.generation += 1;
|
||||
|
||||
// Detect which source files changed.
|
||||
for (module.import_table.items()) |entry| {
|
||||
const file = entry.value;
|
||||
var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
|
||||
defer f.close();
|
||||
|
||||
// TODO handle error here by populating a retryable compile error
|
||||
const stat = try f.stat();
|
||||
const unchanged_metadata =
|
||||
stat.size == file.stat_size and
|
||||
stat.mtime == file.stat_mtime and
|
||||
stat.inode == file.stat_inode;
|
||||
|
||||
if (unchanged_metadata) {
|
||||
log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
|
||||
continue;
|
||||
}
|
||||
|
||||
log.debug("metadata changed: {s}", .{file.sub_file_path});
|
||||
if (file.status == .unloaded_parse_failure) {
|
||||
module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
|
||||
}
|
||||
|
||||
file.unload(module.gpa);
|
||||
// TODO handle error here by populating a retryable compile error
|
||||
try file.finishGettingSource(module.gpa, f, stat);
|
||||
|
||||
module.analyzeFile(file) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => continue,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
// Simulate `_ = @import("std");` which in turn imports start.zig.
|
||||
// Make sure std.zig is inside the import_table. We unconditionally need
|
||||
// it for start.zig.
|
||||
_ = try module.importFile(module.root_pkg, "std");
|
||||
|
||||
// Put a work item in for every known source file to detect if
|
||||
// it changed, and, if so, re-compute ZIR and then queue the job
|
||||
// to update it.
|
||||
try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count());
|
||||
for (module.import_table.items()) |entry| {
|
||||
self.astgen_work_queue.writeItemAssumeCapacity(entry.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1578,13 +1566,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
|
||||
// the previous parse success, including compile errors, but we cannot
|
||||
// emit them until the file succeeds parsing.
|
||||
for (module.failed_decls.items()) |entry| {
|
||||
if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
|
||||
if (entry.key.namespace.file_scope.status == .parse_failure) {
|
||||
continue;
|
||||
}
|
||||
total += 1;
|
||||
}
|
||||
for (module.emit_h_failed_decls.items()) |entry| {
|
||||
if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
|
||||
if (entry.key.namespace.file_scope.status == .parse_failure) {
|
||||
continue;
|
||||
}
|
||||
total += 1;
|
||||
@ -1639,7 +1627,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
|
||||
try AllErrors.add(module, &arena, &errors, entry.value.*);
|
||||
}
|
||||
for (module.failed_decls.items()) |entry| {
|
||||
if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
|
||||
if (entry.key.namespace.file_scope.status == .parse_failure) {
|
||||
// Skip errors for Decls within files that had a parse failure.
|
||||
// We'll try again once parsing succeeds.
|
||||
continue;
|
||||
@ -1647,7 +1635,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
|
||||
try AllErrors.add(module, &arena, &errors, entry.value.*);
|
||||
}
|
||||
for (module.emit_h_failed_decls.items()) |entry| {
|
||||
if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
|
||||
if (entry.key.namespace.file_scope.status == .parse_failure) {
|
||||
// Skip errors for Decls within files that had a parse failure.
|
||||
// We'll try again once parsing succeeds.
|
||||
continue;
|
||||
@ -1719,17 +1707,37 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||
defer main_progress_node.end();
|
||||
if (self.color == .off) progress.terminal = null;
|
||||
|
||||
var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
|
||||
defer c_comp_progress_node.end();
|
||||
// Here we queue up all the AstGen tasks first, followed by C object compilation.
|
||||
// We wait until the AstGen tasks are all completed before proceeding to the
|
||||
// (at least for now) single-threaded main work queue. However, C object compilation
|
||||
// only needs to be finished by the end of this function.
|
||||
|
||||
var zir_prog_node = main_progress_node.start("AstGen", self.astgen_work_queue.count);
|
||||
defer zir_prog_node.end();
|
||||
|
||||
var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
|
||||
defer c_obj_prog_node.end();
|
||||
|
||||
self.work_queue_wait_group.reset();
|
||||
defer self.work_queue_wait_group.wait();
|
||||
|
||||
while (self.c_object_work_queue.readItem()) |c_object| {
|
||||
self.work_queue_wait_group.start();
|
||||
try self.thread_pool.spawn(workerUpdateCObject, .{
|
||||
self, c_object, &c_comp_progress_node, &self.work_queue_wait_group,
|
||||
});
|
||||
{
|
||||
self.astgen_wait_group.reset();
|
||||
defer self.astgen_wait_group.wait();
|
||||
|
||||
while (self.astgen_work_queue.readItem()) |file| {
|
||||
self.astgen_wait_group.start();
|
||||
try self.thread_pool.spawn(workerAstGenFile, .{
|
||||
self, file, &zir_prog_node, &self.astgen_wait_group,
|
||||
});
|
||||
}
|
||||
|
||||
while (self.c_object_work_queue.readItem()) |c_object| {
|
||||
self.work_queue_wait_group.start();
|
||||
try self.thread_pool.spawn(workerUpdateCObject, .{
|
||||
self, c_object, &c_obj_prog_node, &self.work_queue_wait_group,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
while (self.work_queue.readItem()) |work_item| switch (work_item) {
|
||||
@ -2036,6 +2044,28 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||
};
|
||||
}
|
||||
|
||||
fn workerAstGenFile(
|
||||
comp: *Compilation,
|
||||
file: *Module.Scope.File,
|
||||
prog_node: *std.Progress.Node,
|
||||
wg: *WaitGroup,
|
||||
) void {
|
||||
defer wg.finish();
|
||||
|
||||
const mod = comp.bin_file.options.module.?;
|
||||
mod.astGenFile(file, prog_node) catch |err| switch (err) {
|
||||
error.AnalysisFail => return,
|
||||
else => {
|
||||
file.status = .retryable_failure;
|
||||
comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
|
||||
// Swallowing this error is OK because it's implied to be OOM when
|
||||
// there is a missing `failed_files` error message.
|
||||
error.OutOfMemory => {},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
|
||||
var man = comp.cache_parent.obtain();
|
||||
|
||||
@ -2235,7 +2265,32 @@ fn reportRetryableCObjectError(
|
||||
}
|
||||
}
|
||||
|
||||
fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void {
|
||||
fn reportRetryableAstGenError(
|
||||
comp: *Compilation,
|
||||
file: *Module.Scope.File,
|
||||
err: anyerror,
|
||||
) error{OutOfMemory}!void {
|
||||
const mod = comp.bin_file.options.module.?;
|
||||
const gpa = mod.gpa;
|
||||
|
||||
file.status = .retryable_failure;
|
||||
|
||||
const err_msg = try Module.ErrorMsg.create(gpa, .{
|
||||
.container = .{ .file_scope = file },
|
||||
.lazy = .entire_file,
|
||||
}, "unable to load {s}: {s}", .{
|
||||
file.sub_file_path, @errorName(err),
|
||||
});
|
||||
errdefer err_msg.destroy(gpa);
|
||||
|
||||
{
|
||||
const lock = comp.mutex.acquire();
|
||||
defer lock.release();
|
||||
try mod.failed_files.putNoClobber(gpa, file, err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void {
|
||||
if (!build_options.have_llvm) {
|
||||
return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
|
||||
}
|
||||
@ -2302,8 +2357,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
|
||||
|
||||
const c_source_basename = std.fs.path.basename(c_object.src.src_path);
|
||||
|
||||
c_comp_progress_node.activate();
|
||||
var child_progress_node = c_comp_progress_node.start(c_source_basename, 0);
|
||||
c_obj_prog_node.activate();
|
||||
var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
|
||||
child_progress_node.activate();
|
||||
defer child_progress_node.end();
|
||||
|
||||
|
||||
1603
src/Module.zig
1603
src/Module.zig
File diff suppressed because it is too large
Load Diff
25
src/Sema.zig
25
src/Sema.zig
@ -199,10 +199,10 @@ pub fn analyzeBody(
|
||||
.field_val => try sema.zirFieldVal(block, inst),
|
||||
.field_val_named => try sema.zirFieldValNamed(block, inst),
|
||||
.floatcast => try sema.zirFloatcast(block, inst),
|
||||
.fn_type => try sema.zirFnType(block, inst, false),
|
||||
.fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
|
||||
.fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
|
||||
.fn_type_var_args => try sema.zirFnType(block, inst, true),
|
||||
.func => try sema.zirFunc(block, inst, false),
|
||||
.func_extra => try sema.zirFuncExtra(block, inst, false),
|
||||
.func_extra_var_args => try sema.zirFuncExtra(block, inst, true),
|
||||
.func_var_args => try sema.zirFunc(block, inst, true),
|
||||
.has_decl => try sema.zirHasDecl(block, inst),
|
||||
.import => try sema.zirImport(block, inst),
|
||||
.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
|
||||
@ -2513,16 +2513,16 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
|
||||
}
|
||||
}
|
||||
|
||||
fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
|
||||
fn zirFunc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = sema.code.extraData(Zir.Inst.FnType, inst_data.payload_index);
|
||||
const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
|
||||
const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
|
||||
|
||||
return sema.fnTypeCommon(
|
||||
return sema.funcCommon(
|
||||
block,
|
||||
inst_data.src_node,
|
||||
param_types,
|
||||
@ -2532,14 +2532,14 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: b
|
||||
);
|
||||
}
|
||||
|
||||
fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
|
||||
fn zirFuncExtra(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args: bool) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = inst_data.src_node };
|
||||
const extra = sema.code.extraData(Zir.Inst.FnTypeCc, inst_data.payload_index);
|
||||
const extra = sema.code.extraData(Zir.Inst.FuncExtra, inst_data.payload_index);
|
||||
const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
|
||||
|
||||
const cc_tv = try sema.resolveInstConst(block, cc_src, extra.data.cc);
|
||||
@ -2548,7 +2548,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
|
||||
const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
|
||||
const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
|
||||
return sema.mod.fail(&block.base, cc_src, "Unknown calling convention {s}", .{cc_str});
|
||||
return sema.fnTypeCommon(
|
||||
return sema.funcCommon(
|
||||
block,
|
||||
inst_data.src_node,
|
||||
param_types,
|
||||
@ -2558,7 +2558,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index, var_args:
|
||||
);
|
||||
}
|
||||
|
||||
fn fnTypeCommon(
|
||||
fn funcCommon(
|
||||
sema: *Sema,
|
||||
block: *Scope.Block,
|
||||
src_node_offset: i32,
|
||||
@ -3921,9 +3921,6 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
|
||||
error.ImportOutsidePkgPath => {
|
||||
return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
|
||||
},
|
||||
error.FileNotFound => {
|
||||
return mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
|
||||
},
|
||||
else => {
|
||||
// TODO: these errors are file system errors; make sure an update() will
|
||||
// retry this and not cache the file system error, which may be transient.
|
||||
|
||||
141
src/Zir.zig
141
src/Zir.zig
@ -26,8 +26,6 @@ const ir = @import("ir.zig");
|
||||
const Module = @import("Module.zig");
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
|
||||
/// There is always implicitly a `block` instruction at index 0.
|
||||
/// This is so that `break_inline` can break from the root block.
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// In order to store references to strings in fewer bytes, we copy all
|
||||
/// string bytes into here. String bytes can be null. It is up to whomever
|
||||
@ -36,6 +34,12 @@ instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// `string_bytes` array is agnostic to either usage.
|
||||
string_bytes: []u8,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
/// Indexes 0 and 1 are reserved for:
|
||||
/// 0. struct_decl: Ref
|
||||
/// - the main struct decl for this file
|
||||
/// 1. errors_payload_index: u32
|
||||
/// - if this is 0, no compile errors. Otherwise there is a `CompileErrors`
|
||||
/// payload at this index.
|
||||
extra: []u32,
|
||||
|
||||
/// Returns the requested data, as well as the new index which is at the start of the
|
||||
@ -358,16 +362,19 @@ pub const Inst = struct {
|
||||
/// Uses the `pl_node` field. AST is the `@floatCast` syntax.
|
||||
/// Payload is `Bin` with lhs as the dest type, rhs the operand.
|
||||
floatcast,
|
||||
/// Returns a function type, assuming unspecified calling convention.
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `FnType`.
|
||||
fn_type,
|
||||
/// Same as `fn_type` but the function is variadic.
|
||||
fn_type_var_args,
|
||||
/// Returns a function type, with a calling convention instruction operand.
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`.
|
||||
fn_type_cc,
|
||||
/// Same as `fn_type_cc` but the function is variadic.
|
||||
fn_type_cc_var_args,
|
||||
/// Returns a function type, or a function instance, depending on whether
|
||||
/// the body_len is 0. Calling convention is auto.
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `Func`.
|
||||
func,
|
||||
/// Same as `func` but the function is variadic.
|
||||
func_var_args,
|
||||
/// Same as `func` but with extra fields:
|
||||
/// * calling convention
|
||||
/// * extern lib name
|
||||
/// Uses the `pl_node` union field. `payload_index` points to a `FuncExtra`.
|
||||
func_extra,
|
||||
/// Same as `func_extra` but the function is variadic.
|
||||
func_extra_var_args,
|
||||
/// Implements the `@hasDecl` builtin.
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
has_decl,
|
||||
@ -769,10 +776,10 @@ pub const Inst = struct {
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
.field_val_named,
|
||||
.fn_type,
|
||||
.fn_type_var_args,
|
||||
.fn_type_cc,
|
||||
.fn_type_cc_var_args,
|
||||
.func,
|
||||
.func_var_args,
|
||||
.func_extra,
|
||||
.func_extra_var_args,
|
||||
.has_decl,
|
||||
.int,
|
||||
.float,
|
||||
@ -1372,21 +1379,25 @@ pub const Inst = struct {
|
||||
clobbers_len: u32,
|
||||
};
|
||||
|
||||
/// This data is stored inside extra, with trailing parameter type indexes
|
||||
/// according to `param_types_len`.
|
||||
/// Each param type is a `Ref`.
|
||||
pub const FnTypeCc = struct {
|
||||
return_type: Ref,
|
||||
/// Trailing:
|
||||
/// 0. param_type: Ref // for each param_types_len
|
||||
/// 1. body: Index // for each body_len
|
||||
pub const FuncExtra = struct {
|
||||
cc: Ref,
|
||||
/// null terminated string index, or 0 to mean none.
|
||||
lib_name: u32,
|
||||
return_type: Ref,
|
||||
param_types_len: u32,
|
||||
body_len: u32,
|
||||
};
|
||||
|
||||
/// This data is stored inside extra, with trailing parameter type indexes
|
||||
/// according to `param_types_len`.
|
||||
/// Each param type is a `Ref`.
|
||||
pub const FnType = struct {
|
||||
/// Trailing:
|
||||
/// 0. param_type: Ref // for each param_types_len
|
||||
/// 1. body: Index // for each body_len
|
||||
pub const Func = struct {
|
||||
return_type: Ref,
|
||||
param_types_len: u32,
|
||||
body_len: u32,
|
||||
};
|
||||
|
||||
/// This data is stored inside extra, with trailing operands according to `operands_len`.
|
||||
@ -1531,9 +1542,18 @@ pub const Inst = struct {
|
||||
/// align: Ref, // if corresponding bit is set
|
||||
/// default_value: Ref, // if corresponding bit is set
|
||||
/// }
|
||||
/// 3. decl_bits: u32 // for every 16 decls
|
||||
/// - sets of 2 bits:
|
||||
/// 0b0X: whether corresponding decl is pub
|
||||
/// 0bX0: whether corresponding decl is exported
|
||||
/// 4. decl: { // for every decls_len
|
||||
/// name: u32, // null terminated string index
|
||||
/// value: Ref,
|
||||
/// }
|
||||
pub const StructDecl = struct {
|
||||
body_len: u32,
|
||||
fields_len: u32,
|
||||
decls_len: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
@ -1600,6 +1620,26 @@ pub const Inst = struct {
|
||||
/// Offset into `string_bytes`, null terminated.
|
||||
name_start: u32,
|
||||
};
|
||||
|
||||
/// Trailing: `CompileErrors.Item` for each `items_len`.
|
||||
pub const CompileErrors = struct {
|
||||
items_len: u32,
|
||||
|
||||
/// Trailing: `note_payload_index: u32` for each `notes_len`.
|
||||
/// It's a payload index of another `Item`.
|
||||
pub const Item = struct {
|
||||
/// null terminated string index
|
||||
msg: u32,
|
||||
node: ast.Node.Index,
|
||||
/// If node is 0 then this will be populated.
|
||||
token: ast.TokenIndex,
|
||||
/// Can be used in combination with `token`.
|
||||
byte_offset: u32,
|
||||
/// 0 or a payload index of a `Block`, each is a payload
|
||||
/// index of another `Item`.
|
||||
notes: u32,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const SpecialProng = enum { none, @"else", under };
|
||||
@ -1819,10 +1859,10 @@ const Writer = struct {
|
||||
.decl_val_named,
|
||||
=> try self.writeStrTok(stream, inst),
|
||||
|
||||
.fn_type => try self.writeFnType(stream, inst, false),
|
||||
.fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
|
||||
.fn_type_var_args => try self.writeFnType(stream, inst, true),
|
||||
.fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
|
||||
.func => try self.writeFunc(stream, inst, false),
|
||||
.func_extra => try self.writeFuncExtra(stream, inst, false),
|
||||
.func_var_args => try self.writeFunc(stream, inst, true),
|
||||
.func_extra_var_args => try self.writeFuncExtra(stream, inst, true),
|
||||
|
||||
.@"unreachable" => try self.writeUnreachable(stream, inst),
|
||||
|
||||
@ -2383,7 +2423,7 @@ const Writer = struct {
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeFnType(
|
||||
fn writeFunc(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
inst: Inst.Index,
|
||||
@ -2391,23 +2431,41 @@ const Writer = struct {
|
||||
) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
|
||||
const extra = self.code.extraData(Inst.Func, inst_data.payload_index);
|
||||
const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
|
||||
return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, .none, src);
|
||||
const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
|
||||
return self.writeFuncCommon(
|
||||
stream,
|
||||
param_types,
|
||||
extra.data.return_type,
|
||||
var_args,
|
||||
.none,
|
||||
body,
|
||||
src,
|
||||
);
|
||||
}
|
||||
|
||||
fn writeFnTypeCc(
|
||||
fn writeFuncExtra(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
inst: Inst.Index,
|
||||
var_args: bool,
|
||||
) (@TypeOf(stream).Error || error{OutOfMemory})!void {
|
||||
) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
|
||||
const extra = self.code.extraData(Inst.FuncExtra, inst_data.payload_index);
|
||||
const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
|
||||
const cc = extra.data.cc;
|
||||
return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, cc, src);
|
||||
const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
|
||||
return self.writeFuncCommon(
|
||||
stream,
|
||||
param_types,
|
||||
extra.data.return_type,
|
||||
var_args,
|
||||
cc,
|
||||
body,
|
||||
src,
|
||||
);
|
||||
}
|
||||
|
||||
fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
@ -2449,13 +2507,14 @@ const Writer = struct {
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeFnTypeCommon(
|
||||
fn writeFuncCommon(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
param_types: []const Inst.Ref,
|
||||
ret_ty: Inst.Ref,
|
||||
var_args: bool,
|
||||
cc: Inst.Ref,
|
||||
body: []const Inst.Index,
|
||||
src: LazySrcLoc,
|
||||
) !void {
|
||||
try stream.writeAll("[");
|
||||
@ -2467,7 +2526,13 @@ const Writer = struct {
|
||||
try self.writeInstRef(stream, ret_ty);
|
||||
try self.writeOptionalInstRef(stream, ", cc=", cc);
|
||||
try self.writeFlag(stream, ", var_args", var_args);
|
||||
try stream.writeAll(") ");
|
||||
|
||||
try stream.writeAll(", {\n");
|
||||
self.indent += 2;
|
||||
try self.writeBody(stream, body);
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}) ");
|
||||
try self.writeSrc(stream, src);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user