Commit 20b4a2cf2c
Changed files (5)
lib/std/zig.zig
@@ -43,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
return .{ .line = line, .column = column };
}
+/// Returns the standard file system basename of a binary generated by the Zig compiler.
+pub fn binNameAlloc(
+ allocator: *std.mem.Allocator,
+ root_name: []const u8,
+ target: std.Target,
+ output_mode: std.builtin.OutputMode,
+ link_mode: ?std.builtin.LinkMode,
+) error{OutOfMemory}![]u8 {
+ switch (output_mode) {
+ .Exe => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.exeFileExt() }),
+ .Lib => {
+ const suffix = switch (link_mode orelse .Static) {
+ .Static => target.staticLibSuffix(),
+ .Dynamic => target.dynamicLibSuffix(),
+ };
+ return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
+ },
+ .Obj => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.oFileExt() }),
+ }
+}
+
test "" {
@import("std").meta.refAllDecls(@This());
}
src-self-hosted/main.zig
@@ -50,8 +50,7 @@ pub fn log(
const scope_prefix = "(" ++ switch (scope) {
// Uncomment to hide logs
//.compiler,
- .link,
- => return,
+ .link => return,
else => @tagName(scope),
} ++ "): ";
@@ -431,21 +430,7 @@ fn buildOutputType(
std.debug.warn("-fno-emit-bin not supported yet", .{});
process.exit(1);
},
- .yes_default_path => switch (output_mode) {
- .Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
- .Lib => blk: {
- const suffix = switch (link_mode orelse .Static) {
- .Static => target_info.target.staticLibSuffix(),
- .Dynamic => target_info.target.dynamicLibSuffix(),
- };
- break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{
- target_info.target.libPrefix(),
- root_name,
- suffix,
- });
- },
- .Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }),
- },
+ .yes_default_path => try std.zig.binNameAlloc(arena, root_name, target_info.target, output_mode, link_mode),
.yes => |p| p,
};
src-self-hosted/test.zig
@@ -21,32 +21,7 @@ const ErrorMsg = struct {
};
pub const TestContext = struct {
- // TODO: remove these. They are deprecated.
- zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase),
-
- /// TODO: find a way to treat cases as individual tests (shouldn't show "1 test passed" if there are 200 cases)
- zir_cases: std.ArrayList(ZIRCase),
-
- // TODO: remove
- pub const ZIRCompareOutputCase = struct {
- name: []const u8,
- src_list: []const []const u8,
- expected_stdout_list: []const []const u8,
- };
-
- pub const ZIRUpdateType = enum {
- /// A transformation update transforms the input ZIR and tests against
- /// the expected output
- Transformation,
- /// An error update attempts to compile bad code, and ensures that it
- /// fails to compile, and for the expected reasons
- Error,
- /// An execution update compiles and runs the input ZIR, feeding in
- /// provided input and ensuring that the outputs match what is expected
- Execution,
- /// A compilation update checks that the ZIR compiles without any issues
- Compiles,
- };
+ zir_cases: std.ArrayList(Case),
pub const ZIRUpdate = struct {
/// The input to the current update. We simulate an incremental update
@@ -57,58 +32,55 @@ pub const TestContext = struct {
/// you can keep it mostly consistent, with small changes, testing the
/// effects of the incremental compilation.
src: [:0]const u8,
- case: union(ZIRUpdateType) {
- /// The expected output ZIR
+ case: union(enum) {
+ /// A transformation update transforms the input ZIR and tests against
+ /// the expected output ZIR.
Transformation: [:0]const u8,
+ /// An error update attempts to compile bad code, and ensures that it
+ /// fails to compile, and for the expected reasons.
/// A slice containing the expected errors *in sequential order*.
Error: []const ErrorMsg,
-
- /// Input to feed to the program, and expected outputs.
- ///
- /// If stdout, stderr, and exit_code are all null, addZIRCase will
- /// discard the test. To test for successful compilation, use a
- /// dedicated Compile update instead.
- Execution: struct {
- stdin: ?[]const u8,
- stdout: ?[]const u8,
- stderr: ?[]const u8,
- exit_code: ?u8,
- },
- /// A Compiles test checks only that compilation of the given ZIR
- /// succeeds. To test outputs, use an Execution test. It is good to
- /// use a Compiles test before an Execution, as the overhead should
- /// be low (due to incremental compilation) and TODO: provide a way
- /// to check changed / new / etc decls in testing mode
- /// (usingnamespace a debug info struct with a comptime flag?)
- Compiles: void,
+ /// An execution update compiles and runs the input ZIR, feeding in
+ /// provided input and ensuring that the stdout match what is expected.
+ Execution: []const u8,
},
};
- /// A ZIRCase consists of a set of *updates*. A update can transform ZIR,
+ /// A Case consists of a set of *updates*. A update can transform ZIR,
/// compile it, ensure that compilation fails, and more. The same Module is
/// used for each update, so each update's source is treated as a single file
/// being updated by the test harness and incrementally compiled.
- pub const ZIRCase = struct {
+ pub const Case = struct {
name: []const u8,
/// The platform the ZIR targets. For non-native platforms, an emulator
/// such as QEMU is required for tests to complete.
target: std.zig.CrossTarget,
updates: std.ArrayList(ZIRUpdate),
+ output_mode: std.builtin.OutputMode,
+ /// Either ".zir" or ".zig"
+ extension: [4]u8,
/// Adds a subcase in which the module is updated with new ZIR, and the
/// resulting ZIR is validated.
- pub fn addTransform(self: *ZIRCase, src: [:0]const u8, result: [:0]const u8) void {
+ pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
self.updates.append(.{
.src = src,
.case = .{ .Transformation = result },
}) catch unreachable;
}
+ pub fn addCompareOutput(self: *Case, src: [:0]const u8, result: []const u8) void {
+ self.updates.append(.{
+ .src = src,
+ .case = .{ .Execution = result },
+ }) catch unreachable;
+ }
+
/// Adds a subcase in which the module is updated with invalid ZIR, and
/// ensures that compilation fails for the expected reasons.
///
/// Errors must be specified in sequential order.
- pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void {
+ pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {
var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
for (errors) |e, i| {
if (e[0] != ':') {
@@ -146,15 +118,65 @@ pub const TestContext = struct {
}
};
- pub fn addZIRMulti(
+ pub fn addExeZIR(
+ ctx: *TestContext,
+ name: []const u8,
+ target: std.zig.CrossTarget,
+ ) *Case {
+ const case = Case{
+ .name = name,
+ .target = target,
+ .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
+ .output_mode = .Exe,
+ .extension = ".zir".*,
+ };
+ ctx.zir_cases.append(case) catch unreachable;
+ return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
+ }
+
+ pub fn addObjZIR(
+ ctx: *TestContext,
+ name: []const u8,
+ target: std.zig.CrossTarget,
+ ) *Case {
+ const case = Case{
+ .name = name,
+ .target = target,
+ .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
+ .output_mode = .Obj,
+ .extension = ".zir".*,
+ };
+ ctx.zir_cases.append(case) catch unreachable;
+ return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
+ }
+
+ pub fn addExe(
ctx: *TestContext,
name: []const u8,
target: std.zig.CrossTarget,
- ) *ZIRCase {
- const case = ZIRCase{
+ ) *Case {
+ const case = Case{
.name = name,
.target = target,
.updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
+ .output_mode = .Exe,
+ .extension = ".zig".*,
+ };
+ ctx.zir_cases.append(case) catch unreachable;
+ return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
+ }
+
+ pub fn addObj(
+ ctx: *TestContext,
+ name: []const u8,
+ target: std.zig.CrossTarget,
+ ) *Case {
+ const case = Case{
+ .name = name,
+ .target = target,
+ .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
+ .output_mode = .Obj,
+ .extension = ".zig".*,
};
ctx.zir_cases.append(case) catch unreachable;
return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
@@ -163,14 +185,21 @@ pub const TestContext = struct {
pub fn addZIRCompareOutput(
ctx: *TestContext,
name: []const u8,
- src_list: []const []const u8,
- expected_stdout_list: []const []const u8,
+ src: [:0]const u8,
+ expected_stdout: []const u8,
) void {
- ctx.zir_cmp_output_cases.append(.{
- .name = name,
- .src_list = src_list,
- .expected_stdout_list = expected_stdout_list,
- }) catch unreachable;
+ var c = ctx.addExeZIR(name, .{});
+ c.addCompareOutput(src, expected_stdout);
+ }
+
+ pub fn addCompareOutput(
+ ctx: *TestContext,
+ name: []const u8,
+ src: [:0]const u8,
+ expected_stdout: []const u8,
+ ) void {
+ var c = ctx.addExe(name, .{});
+ c.addCompareOutput(src, expected_stdout);
}
pub fn addZIRTransform(
@@ -180,7 +209,7 @@ pub const TestContext = struct {
src: [:0]const u8,
result: [:0]const u8,
) void {
- var c = ctx.addZIRMulti(name, target);
+ var c = ctx.addObjZIR(name, target);
c.addTransform(src, result);
}
@@ -191,20 +220,18 @@ pub const TestContext = struct {
src: [:0]const u8,
expected_errors: []const []const u8,
) void {
- var c = ctx.addZIRMulti(name, target);
+ var c = ctx.addObjZIR(name, target);
c.addError(src, expected_errors);
}
fn init() TestContext {
const allocator = std.heap.page_allocator;
return .{
- .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(allocator),
- .zir_cases = std.ArrayList(ZIRCase).init(allocator),
+ .zir_cases = std.ArrayList(Case).init(allocator),
};
}
fn deinit(self: *TestContext) void {
- self.zir_cmp_output_cases.deinit();
for (self.zir_cases.items) |c| {
for (c.updates.items) |u| {
if (u.case == .Error) {
@@ -235,34 +262,24 @@ pub const TestContext = struct {
progress.refresh();
const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.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();
-
- 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 self.runOneCase(std.testing.allocator, &prg_node, case, info.target);
try std.testing.allocator_instance.validate();
}
}
- fn runOneZIRCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {
+ fn runOneCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: Case, target: std.Target) !void {
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
- const tmp_src_path = "test_case.zir";
+ const root_name = "test_case";
+ const tmp_src_path = try std.fmt.allocPrint(allocator, "{}{}", .{ root_name, case.extension });
+ defer allocator.free(tmp_src_path);
const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
defer root_pkg.destroy();
+ const bin_name = try std.zig.binNameAlloc(allocator, root_name, target, case.output_mode, null);
+ defer allocator.free(bin_name);
+
var module = try Module.init(allocator, .{
.target = target,
// This is an Executable, as opposed to e.g. a *library*. This does
@@ -271,17 +288,17 @@ pub const TestContext = struct {
// TODO: support tests for object file building, and library builds
// and linking. This will require a rework to support multi-file
// tests.
- .output_mode = .Obj,
+ .output_mode = case.output_mode,
// TODO: support testing optimizations
.optimize_mode = .Debug,
.bin_file_dir = tmp.dir,
- .bin_file_path = "test_case.o",
+ .bin_file_path = bin_name,
.root_pkg = root_pkg,
.keep_source_files_loaded = true,
});
defer module.deinit();
- for (case.updates.items) |update| {
+ for (case.updates.items) |update, update_index| {
var update_node = prg_node.start("update", 4);
update_node.activate();
defer update_node.end();
@@ -293,6 +310,7 @@ pub const TestContext = struct {
var module_node = update_node.start("parse/analysis/codegen", null);
module_node.activate();
+ try module.makeBinFileWritable();
try module.update();
module_node.end();
@@ -341,78 +359,41 @@ pub const TestContext = struct {
}
}
},
-
- else => return error.Unimplemented,
- }
- }
- }
-
- fn runOneZIRCmpOutputCase(
- self: *TestContext,
- allocator: *Allocator,
- prg_node: *std.Progress.Node,
- case: ZIRCompareOutputCase,
- target: std.Target,
- ) !void {
- var tmp = std.testing.tmpDir(.{});
- defer tmp.cleanup();
-
- const tmp_src_path = "test-case.zir";
- const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
- defer root_pkg.destroy();
-
- var module = try Module.init(allocator, .{
- .target = target,
- .output_mode = .Exe,
- .optimize_mode = .Debug,
- .bin_file_dir = tmp.dir,
- .bin_file_path = "a.out",
- .root_pkg = root_pkg,
- });
- defer module.deinit();
-
- for (case.src_list) |source, i| {
- var src_node = prg_node.start("update", 2);
- src_node.activate();
- defer src_node.end();
-
- try tmp.dir.writeFile(tmp_src_path, source);
-
- var update_node = src_node.start("parse,analysis,codegen", null);
- update_node.activate();
- try module.makeBinFileWritable();
- try module.update();
- update_node.end();
-
- var exec_result = x: {
- var exec_node = src_node.start("execute", null);
- exec_node.activate();
- defer exec_node.end();
-
- try module.makeBinFileExecutable();
- break :x try std.ChildProcess.exec(.{
- .allocator = allocator,
- .argv = &[_][]const u8{"./a.out"},
- .cwd_dir = tmp.dir,
- });
- };
- defer allocator.free(exec_result.stdout);
- defer allocator.free(exec_result.stderr);
- switch (exec_result.term) {
- .Exited => |code| {
- if (code != 0) {
- std.debug.warn("elf file exited with code {}\n", .{code});
- return error.BinaryBadExitCode;
+ .Execution => |expected_stdout| {
+ var exec_result = x: {
+ var exec_node = update_node.start("execute", null);
+ exec_node.activate();
+ defer exec_node.end();
+
+ try module.makeBinFileExecutable();
+
+ const exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
+ defer allocator.free(exe_path);
+
+ break :x try std.ChildProcess.exec(.{
+ .allocator = allocator,
+ .argv = &[_][]const u8{exe_path},
+ .cwd_dir = tmp.dir,
+ });
+ };
+ defer allocator.free(exec_result.stdout);
+ defer allocator.free(exec_result.stderr);
+ switch (exec_result.term) {
+ .Exited => |code| {
+ if (code != 0) {
+ std.debug.warn("elf file exited with code {}\n", .{code});
+ return error.BinaryBadExitCode;
+ }
+ },
+ else => return error.BinaryCrashed,
+ }
+ if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
+ std.debug.panic(
+ "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
+ .{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
+ );
}
},
- else => return error.BinaryCrashed,
- }
- const expected_stdout = case.expected_stdout_list[i];
- if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
- std.debug.panic(
- "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
- .{ i, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
- );
}
}
}
test/stage2/compare_output.zig
@@ -1,28 +1,121 @@
const std = @import("std");
const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
+// self-hosted does not yet support PE executable files / COFF object files
+// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
+const linux_x64 = std.zig.CrossTarget{
+ .cpu_arch = .x86_64,
+ .os_tag = .linux,
+};
pub fn addCases(ctx: *TestContext) !void {
- // TODO: re-enable these tests.
- // https://github.com/ziglang/zig/issues/1364
+ if (std.Target.current.os.tag != .linux or
+ std.Target.current.cpu.arch != .x86_64)
+ {
+ // TODO implement self-hosted PE (.exe file) linking
+ // TODO implement more ZIR so we don't depend on x86_64-linux
+ return;
+ }
- //// hello world
- //try ctx.testCompareOutputLibC(
- // \\extern fn puts([*]const u8) void;
- // \\pub export fn main() c_int {
- // \\ puts("Hello, world!");
- // \\ return 0;
- // \\}
- //, "Hello, world!" ++ std.cstr.line_sep);
-
- //// function calling another function
- //try ctx.testCompareOutputLibC(
- // \\extern fn puts(s: [*]const u8) void;
- // \\pub export fn main() c_int {
- // \\ return foo("OK");
- // \\}
- // \\fn foo(s: [*]const u8) c_int {
- // \\ puts(s);
- // \\ return 0;
- // \\}
- //, "OK" ++ std.cstr.line_sep);
+ {
+ var case = ctx.addExe("hello world with updates", linux_x64);
+ // Regular old hello world
+ case.addCompareOutput(
+ \\export fn _start() noreturn {
+ \\ print();
+ \\
+ \\ exit();
+ \\}
+ \\
+ \\fn print() void {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (1),
+ \\ [arg1] "{rdi}" (1),
+ \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
+ \\ [arg3] "{rdx}" (14)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ return;
+ \\}
+ \\
+ \\fn exit() noreturn {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (231),
+ \\ [arg1] "{rdi}" (0)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ unreachable;
+ \\}
+ ,
+ "Hello, World!\n",
+ );
+ // Now change the message only
+ case.addCompareOutput(
+ \\export fn _start() noreturn {
+ \\ print();
+ \\
+ \\ exit();
+ \\}
+ \\
+ \\fn print() void {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (1),
+ \\ [arg1] "{rdi}" (1),
+ \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
+ \\ [arg3] "{rdx}" (104)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ return;
+ \\}
+ \\
+ \\fn exit() noreturn {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (231),
+ \\ [arg1] "{rdi}" (0)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ unreachable;
+ \\}
+ ,
+ "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
+ );
+ // Now we print it twice.
+ case.addCompareOutput(
+ \\export fn _start() noreturn {
+ \\ print();
+ \\ print();
+ \\
+ \\ exit();
+ \\}
+ \\
+ \\fn print() void {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (1),
+ \\ [arg1] "{rdi}" (1),
+ \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
+ \\ [arg3] "{rdx}" (104)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ return;
+ \\}
+ \\
+ \\fn exit() noreturn {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (231),
+ \\ [arg1] "{rdi}" (0)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ unreachable;
+ \\}
+ ,
+ \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
+ \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
+ \\
+ );
+ }
}
test/stage2/zir.zig
@@ -86,7 +86,7 @@ pub fn addCases(ctx: *TestContext) void {
);
{
- var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64);
+ var case = ctx.addObjZIR("reference cycle with compile error in the cycle", linux_x64);
case.addTransform(
\\@void = primitive(void)
\\@fnty = fntype([], @void, cc=C)
@@ -207,109 +207,101 @@ pub fn addCases(ctx: *TestContext) void {
return;
}
- ctx.addZIRCompareOutput(
- "hello world ZIR",
- &[_][]const u8{
- \\@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")
- \\
- \\@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(@msg)
- \\
- \\ %len_name = str("len")
- \\ %msg_len_ptr = fieldptr(@msg, %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!
- \\
- },
+ ctx.addZIRCompareOutput("hello world ZIR",
+ \\@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")
+ \\
+ \\@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(@msg)
+ \\
+ \\ %len_name = str("len")
+ \\ %msg_len_ptr = fieldptr(@msg, %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")
+ ,
+ \\Hello, world!
+ \\
);
- ctx.addZIRCompareOutput(
- "function call with no args no return value",
- &[_][]const u8{
- \\@noreturn = primitive(noreturn)
- \\@void = primitive(void)
- \\@usize = primitive(usize)
- \\@0 = int(0)
- \\@1 = int(1)
- \\@2 = int(2)
- \\@3 = int(3)
- \\
- \\@exit0_fnty = fntype([], @noreturn)
- \\@exit0 = fn(@exit0_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")
- \\ %r11 = str("r11")
- \\ %memory = str("memory")
- \\
- \\ %rc = asm(%syscall, @usize,
- \\ volatile=1,
- \\ output=%sysoutreg,
- \\ inputs=[%rax, %rdi],
- \\ clobbers=[%rcx, %r11, %memory],
- \\ args=[%SYS_exit_group, %exit_code])
- \\
- \\ %99 = unreachable()
- \\});
- \\
- \\@start_fnty = fntype([], @noreturn, cc=Naked)
- \\@start = fn(@start_fnty, {
- \\ %0 = call(@exit0, [])
- \\})
- \\@9 = str("_start")
- \\@11 = export(@9, "start")
- },
- &[_][]const u8{""},
- );
+ ctx.addZIRCompareOutput("function call with no args no return value",
+ \\@noreturn = primitive(noreturn)
+ \\@void = primitive(void)
+ \\@usize = primitive(usize)
+ \\@0 = int(0)
+ \\@1 = int(1)
+ \\@2 = int(2)
+ \\@3 = int(3)
+ \\
+ \\@exit0_fnty = fntype([], @noreturn)
+ \\@exit0 = fn(@exit0_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")
+ \\ %r11 = str("r11")
+ \\ %memory = str("memory")
+ \\
+ \\ %rc = asm(%syscall, @usize,
+ \\ volatile=1,
+ \\ output=%sysoutreg,
+ \\ inputs=[%rax, %rdi],
+ \\ clobbers=[%rcx, %r11, %memory],
+ \\ args=[%SYS_exit_group, %exit_code])
+ \\
+ \\ %99 = unreachable()
+ \\});
+ \\
+ \\@start_fnty = fntype([], @noreturn, cc=Naked)
+ \\@start = fn(@start_fnty, {
+ \\ %0 = call(@exit0, [])
+ \\})
+ \\@9 = str("_start")
+ \\@11 = export(@9, "start")
+ , "");
}