self-hosted: fix test regressions
I'm allowing incremental compilation of ZIR modules to be broken. This is not a real use case of ZIR, and the feature requires a lot of code duplication with incremental compilation of Zig AST (which works great).
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = .{},
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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{""},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user