Commit 5aa3f56773
Changed files (9)
test
src-self-hosted/link.zig
@@ -369,7 +369,7 @@ pub const ElfFile = struct {
const file_size = self.options.program_code_size_hint;
const p_align = 0x1000;
const off = self.findFreeSpace(file_size, p_align);
- //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
+ //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
try self.program_headers.append(self.allocator, .{
.p_type = elf.PT_LOAD,
.p_offset = off,
@@ -390,7 +390,7 @@ pub const ElfFile = struct {
// page align.
const p_align = 0x1000;
const off = self.findFreeSpace(file_size, p_align);
- //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
+ //std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
// TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
// we'll need to re-use that function anyway, in case the GOT grows and overlaps something
// else in virtual memory.
@@ -412,7 +412,7 @@ pub const ElfFile = struct {
assert(self.shstrtab.items.len == 0);
try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0
const off = self.findFreeSpace(self.shstrtab.items.len, 1);
- //std.debug.warn("found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
+ //std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len });
try self.sections.append(self.allocator, .{
.sh_name = try self.makeString(".shstrtab"),
.sh_type = elf.SHT_STRTAB,
@@ -470,7 +470,7 @@ pub const ElfFile = struct {
const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
const file_size = self.options.symbol_count_hint * each_size;
const off = self.findFreeSpace(file_size, min_align);
- //std.debug.warn("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
+ //std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
try self.sections.append(self.allocator, .{
.sh_name = try self.makeString(".symtab"),
@@ -586,7 +586,7 @@ pub const ElfFile = struct {
shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1);
}
shstrtab_sect.sh_size = needed_size;
- //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
+ //std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
if (!self.shdr_table_dirty) {
@@ -632,7 +632,7 @@ pub const ElfFile = struct {
for (buf) |*shdr, i| {
shdr.* = self.sections.items[i];
- //std.debug.warn("writing section {}\n", .{shdr.*});
+ //std.log.debug(.link, "writing section {}\n", .{shdr.*});
if (foreign_endian) {
bswapAllFields(elf.Elf64_Shdr, shdr);
}
@@ -956,10 +956,10 @@ pub const ElfFile = struct {
try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
if (self.local_symbol_free_list.popOrNull()) |i| {
- //std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
+ //std.log.debug(.link, "reusing symbol index {} for {}\n", .{i, decl.name});
decl.link.local_sym_index = i;
} else {
- //std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
+ //std.log.debug(.link, "allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
_ = self.local_symbols.addOneAssumeCapacity();
}
@@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
!mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
if (need_realloc) {
const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
- //std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
+ //std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
if (vaddr != local_sym.st_value) {
local_sym.st_value = vaddr;
- //std.debug.warn(" (writing new offset table entry)\n", .{});
+ //std.log.debug(.link, " (writing new offset table entry)\n", .{});
self.offset_table.items[decl.link.offset_table_index] = vaddr;
try self.writeOffsetTableEntry(decl.link.offset_table_index);
}
@@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
const decl_name = mem.spanZ(decl.name);
const name_str_index = try self.makeString(decl_name);
const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
- //std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
+ //std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
errdefer self.freeTextBlock(&decl.link);
local_sym.* = .{
@@ -1307,7 +1307,6 @@ pub const ElfFile = struct {
.p32 => @sizeOf(elf.Elf32_Sym),
.p64 => @sizeOf(elf.Elf64_Sym),
};
- //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
switch (self.ptr_width) {
src-self-hosted/main.zig
@@ -38,6 +38,30 @@ const usage =
\\
;
+pub fn log(
+ comptime level: std.log.Level,
+ comptime scope: @TypeOf(.EnumLiteral),
+ comptime format: []const u8,
+ args: var,
+) void {
+ if (@enumToInt(level) > @enumToInt(std.log.level))
+ return;
+
+ const scope_prefix = "(" ++ switch (scope) {
+ // Uncomment to hide logs
+ //.compiler,
+ .link,
+ => return,
+
+ else => @tagName(scope),
+ } ++ "): ";
+
+ const prefix = "[" ++ @tagName(level) ++ "] " ++ scope_prefix;
+
+ // Print the message to stderr, silently ignoring any errors
+ std.debug.print(prefix ++ format, args);
+}
+
pub fn main() !void {
// TODO general purpose allocator in the zig std lib
const gpa = if (std.builtin.link_libc) std.heap.c_allocator else std.heap.page_allocator;
@@ -450,6 +474,7 @@ fn buildOutputType(
.link_mode = link_mode,
.object_format = object_format,
.optimize_mode = build_mode,
+ .keep_source_files_loaded = zir_out_path != null,
});
defer module.deinit();
src-self-hosted/Module.zig
@@ -69,6 +69,8 @@ next_anon_name_index: usize = 0,
/// contains Decls that need to be deleted if they end up having no references to them.
deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
+keep_source_files_loaded: bool,
+
const DeclTable = std.HashMap(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql);
const WorkItem = union(enum) {
@@ -580,11 +582,13 @@ pub const Scope = struct {
.loaded_success => {
self.contents.module.deinit(allocator);
allocator.destroy(self.contents.module);
+ self.contents = .{ .not_available = {} };
self.status = .unloaded_success;
},
.loaded_sema_failure => {
self.contents.module.deinit(allocator);
allocator.destroy(self.contents.module);
+ self.contents = .{ .not_available = {} };
self.status = .unloaded_sema_failure;
},
}
@@ -719,6 +723,7 @@ pub const InitOptions = struct {
link_mode: ?std.builtin.LinkMode = null,
object_format: ?std.builtin.ObjectFormat = null,
optimize_mode: std.builtin.Mode = .Debug,
+ keep_source_files_loaded: bool = false,
};
pub fn init(gpa: *Allocator, options: InitOptions) !Module {
@@ -772,6 +777,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
.failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa),
.failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa),
.work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
+ .keep_source_files_loaded = options.keep_source_files_loaded,
};
}
@@ -869,21 +875,22 @@ pub fn update(self: *Module) !void {
try self.performAllTheWork();
// Process the deletion set.
- for (self.deletion_set.items) |decl| {
+ while (self.deletion_set.popOrNull()) |decl| {
if (decl.dependants.items.len != 0) {
decl.deletion_flag = false;
continue;
}
try self.deleteDecl(decl);
}
- self.deletion_set.shrink(self.allocator, 0);
self.link_error_flags = self.bin_file.error_flags;
// If there are any errors, we anticipate the source files being loaded
// to report error messages. Otherwise we unload all source files to save memory.
if (self.totalErrorCount() == 0) {
- self.root_scope.unload(self.allocator);
+ if (!self.keep_source_files_loaded) {
+ self.root_scope.unload(self.allocator);
+ }
try self.bin_file.flush();
}
}
@@ -1025,7 +1032,6 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
defer tracy.end();
const subsequent_analysis = switch (decl.analysis) {
- .complete => return,
.in_progress => unreachable,
.sema_failure,
@@ -1035,7 +1041,11 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
.codegen_failure_retryable,
=> return error.AnalysisFail,
- .outdated => blk: {
+ .complete, .outdated => blk: {
+ if (decl.generation == self.generation) {
+ assert(decl.analysis == .complete);
+ return;
+ }
//std.debug.warn("re-analyzing {}\n", .{decl.name});
// The exports this Decl performs will be re-discovered, so we remove them here
@@ -1044,10 +1054,9 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
// Dependencies will be re-discovered, so we remove them here prior to re-analysis.
for (decl.dependencies.items) |dep| {
dep.removeDependant(decl);
- if (dep.dependants.items.len == 0) {
+ if (dep.dependants.items.len == 0 and !dep.deletion_flag) {
// We don't perform a deletion here, because this Decl or another one
// may end up referencing it before the update is complete.
- assert(!dep.deletion_flag);
dep.deletion_flag = true;
try self.deletion_set.append(self.allocator, dep);
}
@@ -1773,6 +1782,9 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
}
}
}
+ for (exports_to_resolve.items) |export_decl| {
+ _ = try self.resolveZirDecl(&root_scope.base, export_decl);
+ }
{
// Handle explicitly deleted decls from the source code. Not to be confused
// with when we delete decls because they are no longer referenced.
@@ -1782,9 +1794,6 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
try self.deleteDecl(kv.key);
}
}
- for (exports_to_resolve.items) |export_decl| {
- _ = try self.resolveZirDecl(&root_scope.base, export_decl);
- }
}
fn deleteDecl(self: *Module, decl: *Decl) !void {
@@ -1800,10 +1809,9 @@ fn deleteDecl(self: *Module, decl: *Decl) !void {
// Remove itself from its dependencies, because we are about to destroy the decl pointer.
for (decl.dependencies.items) |dep| {
dep.removeDependant(decl);
- if (dep.dependants.items.len == 0) {
+ if (dep.dependants.items.len == 0 and !dep.deletion_flag) {
// We don't recursively perform a deletion here, because during the update,
// another reference to it may turn up.
- assert(!dep.deletion_flag);
dep.deletion_flag = true;
self.deletion_set.appendAssumeCapacity(dep);
}
@@ -2026,9 +2034,10 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
};
const decl = try self.resolveCompleteZirDecl(scope, entry.decl);
const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);
- const result = try self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
- old_inst.analyzed_inst = result;
- return result;
+ // Note: it would be tempting here to store the result into old_inst.analyzed_inst field,
+ // but this would prevent the analyzeDeclRef from happening, which is needed to properly
+ // detect Decl dependencies and dependency failures on updates.
+ return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
}
fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
src-self-hosted/test.zig
@@ -226,20 +226,36 @@ pub const TestContext = struct {
for (self.zir_cases.items) |case| {
std.testing.base_allocator_instance.reset();
+
+ var prg_node = root_node.start(case.name, case.updates.items.len);
+ prg_node.activate();
+ defer prg_node.end();
+
+ // So that we can see which test case failed when the leak checker goes off.
+ progress.refresh();
+
const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
- try self.runOneZIRCase(std.testing.allocator, root_node, case, info.target);
+ try self.runOneZIRCase(std.testing.allocator, &prg_node, case, info.target);
try std.testing.allocator_instance.validate();
}
// TODO: wipe the rest of this function
for (self.zir_cmp_output_cases.items) |case| {
std.testing.base_allocator_instance.reset();
- try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target);
+
+ var prg_node = root_node.start(case.name, case.src_list.len);
+ prg_node.activate();
+ defer prg_node.end();
+
+ // So that we can see which test case failed when the leak checker goes off.
+ progress.refresh();
+
+ try self.runOneZIRCmpOutputCase(std.testing.allocator, &prg_node, case, native_info.target);
try std.testing.allocator_instance.validate();
}
}
- fn runOneZIRCase(self: *TestContext, allocator: *Allocator, root_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {
+ fn runOneZIRCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
@@ -247,10 +263,6 @@ pub const TestContext = struct {
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
defer root_pkg.destroy();
- var prg_node = root_node.start(case.name, case.updates.items.len);
- prg_node.activate();
- defer prg_node.end();
-
var module = try Module.init(allocator, .{
.target = target,
// This is an Executable, as opposed to e.g. a *library*. This does
@@ -265,6 +277,7 @@ pub const TestContext = struct {
.bin_file_dir = tmp.dir,
.bin_file_path = "test_case.o",
.root_pkg = root_pkg,
+ .keep_source_files_loaded = true,
});
defer module.deinit();
@@ -329,7 +342,7 @@ pub const TestContext = struct {
}
},
- else => return error.unimplemented,
+ else => return error.Unimplemented,
}
}
}
@@ -337,7 +350,7 @@ pub const TestContext = struct {
fn runOneZIRCmpOutputCase(
self: *TestContext,
allocator: *Allocator,
- root_node: *std.Progress.Node,
+ prg_node: *std.Progress.Node,
case: ZIRCompareOutputCase,
target: std.Target,
) !void {
@@ -348,10 +361,6 @@ pub const TestContext = struct {
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
defer root_pkg.destroy();
- var prg_node = root_node.start(case.name, case.src_list.len);
- prg_node.activate();
- defer prg_node.end();
-
var module = try Module.init(allocator, .{
.target = target,
.output_mode = .Exe,
src-self-hosted/tracy.zig
@@ -1,6 +1,6 @@
pub const std = @import("std");
-pub const enable = @import("build_options").enable_tracy;
+pub const enable = if (std.builtin.is_test) false else @import("build_options").enable_tracy;
extern fn ___tracy_emit_zone_begin_callstack(
srcloc: *const ___tracy_source_location_data,
src-self-hosted/type.zig
@@ -113,6 +113,12 @@ pub const Type = extern union {
.Undefined => return true,
.Null => return true,
.Pointer => {
+ // Hot path for common case:
+ if (a.cast(Payload.SingleConstPointer)) |a_payload| {
+ if (b.cast(Payload.SingleConstPointer)) |b_payload| {
+ return eql(a_payload.pointee_type, b_payload.pointee_type);
+ }
+ }
const is_slice_a = isSlice(a);
const is_slice_b = isSlice(b);
if (is_slice_a != is_slice_b)
src-self-hosted/zir.zig
@@ -710,8 +710,9 @@ pub const Module = struct {
} else if (inst.cast(Inst.DeclValInModule)) |decl_val| {
try stream.print("@{}", .{decl_val.positionals.decl.name});
} else {
- //try stream.print("?", .{});
- unreachable;
+ // This should be unreachable in theory, but since ZIR is used for debugging the compiler
+ // we output some debug text instead.
+ try stream.print("?{}?", .{@tagName(inst.tag)});
}
}
};
@@ -1175,6 +1176,39 @@ const EmitZIR = struct {
// Emit all the decls.
for (src_decls.items) |ir_decl| {
+ switch (ir_decl.analysis) {
+ .unreferenced => continue,
+ .complete => {},
+ .in_progress => unreachable,
+ .outdated => unreachable,
+
+ .sema_failure,
+ .sema_failure_retryable,
+ .codegen_failure,
+ .dependency_failure,
+ .codegen_failure_retryable,
+ => if (self.old_module.failed_decls.getValue(ir_decl)) |err_msg| {
+ const fail_inst = try self.arena.allocator.create(Inst.CompileError);
+ fail_inst.* = .{
+ .base = .{
+ .src = ir_decl.src(),
+ .tag = Inst.CompileError.base_tag,
+ },
+ .positionals = .{
+ .msg = try self.arena.allocator.dupe(u8, err_msg.msg),
+ },
+ .kw_args = .{},
+ };
+ const decl = try self.arena.allocator.create(Decl);
+ decl.* = .{
+ .name = mem.spanZ(ir_decl.name),
+ .contents_hash = undefined,
+ .inst = &fail_inst.base,
+ };
+ try self.decls.append(self.allocator, decl);
+ continue;
+ },
+ }
if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
for (exports) |module_export| {
const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
@@ -1199,20 +1233,27 @@ const EmitZIR = struct {
}
}
- fn resolveInst(self: *EmitZIR, inst_table: *std.AutoHashMap(*ir.Inst, *Inst), inst: *ir.Inst) !*Inst {
+ const ZirBody = struct {
+ inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
+ instructions: *std.ArrayList(*Inst),
+ };
+
+ fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst {
if (inst.cast(ir.Inst.Constant)) |const_inst| {
- const new_decl = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
+ const new_inst = if (const_inst.val.cast(Value.Payload.Function)) |func_pl| blk: {
const owner_decl = func_pl.func.owner_decl;
break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
} else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {
- break :blk try self.emitDeclRef(inst.src, declref.decl);
+ const decl_ref = try self.emitDeclRef(inst.src, declref.decl);
+ try new_body.instructions.append(decl_ref);
+ break :blk decl_ref;
} else blk: {
break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
};
- try inst_table.putNoClobber(inst, new_decl);
- return new_decl;
+ try new_body.inst_table.putNoClobber(inst, new_inst);
+ return new_inst;
} else {
- return inst_table.getValue(inst).?;
+ return new_body.inst_table.getValue(inst).?;
}
}
@@ -1419,6 +1460,10 @@ const EmitZIR = struct {
inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
instructions: *std.ArrayList(*Inst),
) Allocator.Error!void {
+ const new_body = ZirBody{
+ .inst_table = inst_table,
+ .instructions = instructions,
+ };
for (body.instructions) |inst| {
const new_inst = switch (inst.tag) {
.breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
@@ -1428,7 +1473,7 @@ const EmitZIR = struct {
const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
for (args) |*elem, i| {
- elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]);
+ elem.* = try self.resolveInst(new_body, old_inst.args.args[i]);
}
new_inst.* = .{
.base = .{
@@ -1436,7 +1481,7 @@ const EmitZIR = struct {
.tag = Inst.Call.base_tag,
},
.positionals = .{
- .func = try self.resolveInst(inst_table, old_inst.args.func),
+ .func = try self.resolveInst(new_body, old_inst.args.func),
.args = args,
},
.kw_args = .{},
@@ -1453,7 +1498,7 @@ const EmitZIR = struct {
.tag = Inst.Return.base_tag,
},
.positionals = .{
- .operand = try self.resolveInst(inst_table, old_inst.args.operand),
+ .operand = try self.resolveInst(new_body, old_inst.args.operand),
},
.kw_args = .{},
};
@@ -1477,7 +1522,7 @@ const EmitZIR = struct {
const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
for (args) |*elem, i| {
- elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]);
+ elem.* = try self.resolveInst(new_body, old_inst.args.args[i]);
}
new_inst.* = .{
@@ -1511,7 +1556,7 @@ const EmitZIR = struct {
.tag = Inst.PtrToInt.base_tag,
},
.positionals = .{
- .ptr = try self.resolveInst(inst_table, old_inst.args.ptr),
+ .ptr = try self.resolveInst(new_body, old_inst.args.ptr),
},
.kw_args = .{},
};
@@ -1527,7 +1572,7 @@ const EmitZIR = struct {
},
.positionals = .{
.dest_type = (try self.emitType(inst.src, inst.ty)).inst,
- .operand = try self.resolveInst(inst_table, old_inst.args.operand),
+ .operand = try self.resolveInst(new_body, old_inst.args.operand),
},
.kw_args = .{},
};
@@ -1542,8 +1587,8 @@ const EmitZIR = struct {
.tag = Inst.Cmp.base_tag,
},
.positionals = .{
- .lhs = try self.resolveInst(inst_table, old_inst.args.lhs),
- .rhs = try self.resolveInst(inst_table, old_inst.args.rhs),
+ .lhs = try self.resolveInst(new_body, old_inst.args.lhs),
+ .rhs = try self.resolveInst(new_body, old_inst.args.rhs),
.op = old_inst.args.op,
},
.kw_args = .{},
@@ -1569,7 +1614,7 @@ const EmitZIR = struct {
.tag = Inst.CondBr.base_tag,
},
.positionals = .{
- .condition = try self.resolveInst(inst_table, old_inst.args.condition),
+ .condition = try self.resolveInst(new_body, old_inst.args.condition),
.true_body = .{ .instructions = true_body.toOwnedSlice() },
.false_body = .{ .instructions = false_body.toOwnedSlice() },
},
@@ -1586,7 +1631,7 @@ const EmitZIR = struct {
.tag = Inst.IsNull.base_tag,
},
.positionals = .{
- .operand = try self.resolveInst(inst_table, old_inst.args.operand),
+ .operand = try self.resolveInst(new_body, old_inst.args.operand),
},
.kw_args = .{},
};
@@ -1601,7 +1646,7 @@ const EmitZIR = struct {
.tag = Inst.IsNonNull.base_tag,
},
.positionals = .{
- .operand = try self.resolveInst(inst_table, old_inst.args.operand),
+ .operand = try self.resolveInst(new_body, old_inst.args.operand),
},
.kw_args = .{},
};
test/stage2/compile_errors.zig
@@ -27,9 +27,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ %0 = call(@notafunc, [])
\\})
\\@0 = str("_start")
- \\@1 = ref(@0)
- \\@2 = export(@1, @start)
- , &[_][]const u8{":5:13: error: use of undeclared identifier 'notafunc'"});
+ \\@1 = export(@0, "start")
+ , &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
// TODO: this error should occur at the call site, not the fntype decl
ctx.addZIRError("call naked function", linux_x64,
@@ -41,8 +40,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ %0 = call(@s, [])
\\})
\\@0 = str("_start")
- \\@1 = ref(@0)
- \\@2 = export(@1, @start)
+ \\@1 = export(@0, "start")
, &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
// TODO: re-enable these tests.
test/stage2/zir.zig
@@ -14,23 +14,21 @@ pub fn addCases(ctx: *TestContext) void {
\\@fnty = fntype([], @void, cc=C)
\\
\\@9 = str("entry")
- \\@10 = ref(@9)
- \\@11 = export(@10, @entry)
+ \\@11 = export(@9, "entry")
\\
\\@entry = fn(@fnty, {
- \\ %11 = return()
+ \\ %11 = returnvoid()
\\})
,
\\@void = primitive(void)
\\@fnty = fntype([], @void, cc=C)
- \\@9 = str("entry")
- \\@10 = ref(@9)
- \\@unnamed$6 = str("entry")
- \\@unnamed$7 = ref(@unnamed$6)
- \\@unnamed$8 = export(@unnamed$7, @entry)
- \\@unnamed$10 = fntype([], @void, cc=C)
- \\@entry = fn(@unnamed$10, {
- \\ %0 = return()
+ \\@9 = declref("9$0")
+ \\@9$0 = str("entry")
+ \\@unnamed$4 = str("entry")
+ \\@unnamed$5 = export(@unnamed$4, "entry")
+ \\@unnamed$6 = fntype([], @void, cc=C)
+ \\@entry = fn(@unnamed$6, {
+ \\ %0 = returnvoid()
\\})
\\
);
@@ -45,11 +43,10 @@ pub fn addCases(ctx: *TestContext) void {
\\
\\@entry = fn(@fnty, {
\\ %a = str("\x32\x08\x01\x0a")
- \\ %aref = ref(%a)
- \\ %eptr0 = elemptr(%aref, @0)
- \\ %eptr1 = elemptr(%aref, @1)
- \\ %eptr2 = elemptr(%aref, @2)
- \\ %eptr3 = elemptr(%aref, @3)
+ \\ %eptr0 = elemptr(%a, @0)
+ \\ %eptr1 = elemptr(%a, @1)
+ \\ %eptr2 = elemptr(%a, @2)
+ \\ %eptr3 = elemptr(%a, @3)
\\ %v0 = deref(%eptr0)
\\ %v1 = deref(%eptr1)
\\ %v2 = deref(%eptr2)
@@ -61,15 +58,14 @@ pub fn addCases(ctx: *TestContext) void {
\\ %expected = int(69)
\\ %ok = cmp(%result, eq, %expected)
\\ %10 = condbr(%ok, {
- \\ %11 = return()
+ \\ %11 = returnvoid()
\\ }, {
\\ %12 = breakpoint()
\\ })
\\})
\\
\\@9 = str("entry")
- \\@10 = ref(@9)
- \\@11 = export(@10, @entry)
+ \\@11 = export(@9, "entry")
,
\\@void = primitive(void)
\\@fnty = fntype([], @void, cc=C)
@@ -77,16 +73,15 @@ pub fn addCases(ctx: *TestContext) void {
\\@1 = int(1)
\\@2 = int(2)
\\@3 = int(3)
- \\@unnamed$7 = fntype([], @void, cc=C)
- \\@entry = fn(@unnamed$7, {
- \\ %0 = return()
+ \\@unnamed$6 = fntype([], @void, cc=C)
+ \\@entry = fn(@unnamed$6, {
+ \\ %0 = returnvoid()
\\})
- \\@a = str("2\x08\x01\n")
- \\@9 = str("entry")
- \\@10 = ref(@9)
- \\@unnamed$14 = str("entry")
- \\@unnamed$15 = ref(@unnamed$14)
- \\@unnamed$16 = export(@unnamed$15, @entry)
+ \\@entry$1 = str("2\x08\x01\n")
+ \\@9 = declref("9$0")
+ \\@9$0 = str("entry")
+ \\@unnamed$11 = str("entry")
+ \\@unnamed$12 = export(@unnamed$11, "entry")
\\
);
@@ -97,45 +92,43 @@ pub fn addCases(ctx: *TestContext) void {
\\@fnty = fntype([], @void, cc=C)
\\
\\@9 = str("entry")
- \\@10 = ref(@9)
- \\@11 = export(@10, @entry)
+ \\@11 = export(@9, "entry")
\\
\\@entry = fn(@fnty, {
\\ %0 = call(@a, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
\\@a = fn(@fnty, {
\\ %0 = call(@b, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
\\@b = fn(@fnty, {
\\ %0 = call(@a, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
,
\\@void = primitive(void)
\\@fnty = fntype([], @void, cc=C)
- \\@9 = str("entry")
- \\@10 = ref(@9)
- \\@unnamed$6 = str("entry")
- \\@unnamed$7 = ref(@unnamed$6)
- \\@unnamed$8 = export(@unnamed$7, @entry)
- \\@unnamed$12 = fntype([], @void, cc=C)
- \\@entry = fn(@unnamed$12, {
+ \\@9 = declref("9$0")
+ \\@9$0 = str("entry")
+ \\@unnamed$4 = str("entry")
+ \\@unnamed$5 = export(@unnamed$4, "entry")
+ \\@unnamed$6 = fntype([], @void, cc=C)
+ \\@entry = fn(@unnamed$6, {
\\ %0 = call(@a, [], modifier=auto)
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
- \\@unnamed$17 = fntype([], @void, cc=C)
- \\@a = fn(@unnamed$17, {
+ \\@unnamed$8 = fntype([], @void, cc=C)
+ \\@a = fn(@unnamed$8, {
\\ %0 = call(@b, [], modifier=auto)
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
- \\@unnamed$22 = fntype([], @void, cc=C)
- \\@b = fn(@unnamed$22, {
+ \\@unnamed$10 = fntype([], @void, cc=C)
+ \\@b = fn(@unnamed$10, {
\\ %0 = call(@a, [], modifier=auto)
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
);
@@ -145,27 +138,26 @@ pub fn addCases(ctx: *TestContext) void {
\\@fnty = fntype([], @void, cc=C)
\\
\\@9 = str("entry")
- \\@10 = ref(@9)
- \\@11 = export(@10, @entry)
+ \\@11 = export(@9, "entry")
\\
\\@entry = fn(@fnty, {
\\ %0 = call(@a, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
\\@a = fn(@fnty, {
\\ %0 = call(@b, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
\\@b = fn(@fnty, {
\\ %9 = compileerror("message")
\\ %0 = call(@a, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
,
&[_][]const u8{
- ":19:21: error: message",
+ ":18:21: error: message",
},
);
// Now we remove the call to `a`. `a` and `b` form a cycle, but no entry points are
@@ -176,34 +168,32 @@ pub fn addCases(ctx: *TestContext) void {
\\@fnty = fntype([], @void, cc=C)
\\
\\@9 = str("entry")
- \\@10 = ref(@9)
- \\@11 = export(@10, @entry)
+ \\@11 = export(@9, "entry")
\\
\\@entry = fn(@fnty, {
- \\ %1 = return()
+ \\ %0 = returnvoid()
\\})
\\
\\@a = fn(@fnty, {
\\ %0 = call(@b, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
\\
\\@b = fn(@fnty, {
\\ %9 = compileerror("message")
\\ %0 = call(@a, [])
- \\ %1 = return()
+ \\ %1 = returnvoid()
\\})
,
\\@void = primitive(void)
\\@fnty = fntype([], @void, cc=C)
- \\@9 = str("entry")
- \\@10 = ref(@9)
- \\@unnamed$6 = str("entry")
- \\@unnamed$7 = ref(@unnamed$6)
- \\@unnamed$8 = export(@unnamed$7, @entry)
- \\@unnamed$10 = fntype([], @void, cc=C)
- \\@entry = fn(@unnamed$10, {
- \\ %0 = return()
+ \\@9 = declref("9$2")
+ \\@9$2 = str("entry")
+ \\@unnamed$4 = str("entry")
+ \\@unnamed$5 = export(@unnamed$4, "entry")
+ \\@unnamed$6 = fntype([], @void, cc=C)
+ \\@entry = fn(@unnamed$6, {
+ \\ %0 = returnvoid()
\\})
\\
);
@@ -218,7 +208,7 @@ pub fn addCases(ctx: *TestContext) void {
}
ctx.addZIRCompareOutput(
- "hello world ZIR, update msg",
+ "hello world ZIR",
&[_][]const u8{
\\@noreturn = primitive(noreturn)
\\@void = primitive(void)
@@ -272,125 +262,10 @@ pub fn addCases(ctx: *TestContext) void {
\\
\\@9 = str("_start")
\\@11 = export(@9, "start")
- ,
- \\@noreturn = primitive(noreturn)
- \\@void = primitive(void)
- \\@usize = primitive(usize)
- \\@0 = int(0)
- \\@1 = int(1)
- \\@2 = int(2)
- \\@3 = int(3)
- \\
- \\@msg = str("Hello, world!\n")
- \\@msg2 = str("HELL WORLD\n")
- \\
- \\@start_fnty = fntype([], @noreturn, cc=Naked)
- \\@start = fn(@start_fnty, {
- \\ %SYS_exit_group = int(231)
- \\ %exit_code = as(@usize, @0)
- \\
- \\ %syscall = str("syscall")
- \\ %sysoutreg = str("={rax}")
- \\ %rax = str("{rax}")
- \\ %rdi = str("{rdi}")
- \\ %rcx = str("rcx")
- \\ %rdx = str("{rdx}")
- \\ %rsi = str("{rsi}")
- \\ %r11 = str("r11")
- \\ %memory = str("memory")
- \\
- \\ %SYS_write = as(@usize, @1)
- \\ %STDOUT_FILENO = as(@usize, @1)
- \\
- \\ %msg_addr = ptrtoint(@msg2)
- \\
- \\ %len_name = str("len")
- \\ %msg_len_ptr = fieldptr(@msg2, %len_name)
- \\ %msg_len = deref(%msg_len_ptr)
- \\ %rc_write = asm(%syscall, @usize,
- \\ volatile=1,
- \\ output=%sysoutreg,
- \\ inputs=[%rax, %rdi, %rsi, %rdx],
- \\ clobbers=[%rcx, %r11, %memory],
- \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
- \\
- \\ %rc_exit = asm(%syscall, @usize,
- \\ volatile=1,
- \\ output=%sysoutreg,
- \\ inputs=[%rax, %rdi],
- \\ clobbers=[%rcx, %r11, %memory],
- \\ args=[%SYS_exit_group, %exit_code])
- \\
- \\ %99 = unreachable()
- \\});
- \\
- \\@9 = str("_start")
- \\@11 = export(@9, "start")
- ,
- \\@noreturn = primitive(noreturn)
- \\@void = primitive(void)
- \\@usize = primitive(usize)
- \\@0 = int(0)
- \\@1 = int(1)
- \\@2 = int(2)
- \\@3 = int(3)
- \\
- \\@msg = str("Hello, world!\n")
- \\@msg2 = str("Editing the same msg2 decl but this time with a much longer message which will\ncause the data to need to be relocated in virtual address space.\n")
- \\
- \\@start_fnty = fntype([], @noreturn, cc=Naked)
- \\@start = fn(@start_fnty, {
- \\ %SYS_exit_group = int(231)
- \\ %exit_code = as(@usize, @0)
- \\
- \\ %syscall = str("syscall")
- \\ %sysoutreg = str("={rax}")
- \\ %rax = str("{rax}")
- \\ %rdi = str("{rdi}")
- \\ %rcx = str("rcx")
- \\ %rdx = str("{rdx}")
- \\ %rsi = str("{rsi}")
- \\ %r11 = str("r11")
- \\ %memory = str("memory")
- \\
- \\ %SYS_write = as(@usize, @1)
- \\ %STDOUT_FILENO = as(@usize, @1)
- \\
- \\ %msg_addr = ptrtoint(@msg2)
- \\
- \\ %len_name = str("len")
- \\ %msg_len_ptr = fieldptr(@msg2, %len_name)
- \\ %msg_len = deref(%msg_len_ptr)
- \\ %rc_write = asm(%syscall, @usize,
- \\ volatile=1,
- \\ output=%sysoutreg,
- \\ inputs=[%rax, %rdi, %rsi, %rdx],
- \\ clobbers=[%rcx, %r11, %memory],
- \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
- \\
- \\ %rc_exit = asm(%syscall, @usize,
- \\ volatile=1,
- \\ output=%sysoutreg,
- \\ inputs=[%rax, %rdi],
- \\ clobbers=[%rcx, %r11, %memory],
- \\ args=[%SYS_exit_group, %exit_code])
- \\
- \\ %99 = unreachable()
- \\});
- \\
- \\@9 = str("_start")
- \\@11 = export(@9, "start")
},
&[_][]const u8{
\\Hello, world!
\\
- ,
- \\HELL WORLD
- \\
- ,
- \\Editing the same msg2 decl but this time with a much longer message which will
- \\cause the data to need to be relocated in virtual address space.
- \\
},
);
@@ -405,26 +280,18 @@ pub fn addCases(ctx: *TestContext) void {
\\@2 = int(2)
\\@3 = int(3)
\\
- \\@syscall_array = str("syscall")
- \\@sysoutreg_array = str("={rax}")
- \\@rax_array = str("{rax}")
- \\@rdi_array = str("{rdi}")
- \\@rcx_array = str("rcx")
- \\@r11_array = str("r11")
- \\@memory_array = str("memory")
- \\
\\@exit0_fnty = fntype([], @noreturn)
\\@exit0 = fn(@exit0_fnty, {
\\ %SYS_exit_group = int(231)
\\ %exit_code = as(@usize, @0)
\\
- \\ %syscall = ref(@syscall_array)
- \\ %sysoutreg = ref(@sysoutreg_array)
- \\ %rax = ref(@rax_array)
- \\ %rdi = ref(@rdi_array)
- \\ %rcx = ref(@rcx_array)
- \\ %r11 = ref(@r11_array)
- \\ %memory = ref(@memory_array)
+ \\ %syscall = str("syscall")
+ \\ %sysoutreg = str("={rax}")
+ \\ %rax = str("{rax}")
+ \\ %rdi = str("{rdi}")
+ \\ %rcx = str("rcx")
+ \\ %r11 = str("r11")
+ \\ %memory = str("memory")
\\
\\ %rc = asm(%syscall, @usize,
\\ volatile=1,
@@ -441,8 +308,7 @@ pub fn addCases(ctx: *TestContext) void {
\\ %0 = call(@exit0, [])
\\})
\\@9 = str("_start")
- \\@10 = ref(@9)
- \\@11 = export(@10, @start)
+ \\@11 = export(@9, "start")
},
&[_][]const u8{""},
);