From b4eac0414a01b1096e8dd7e89455db88f19789cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 11 Jun 2020 01:22:07 -0400 Subject: stage2: hook up Zig AST to ZIR * Introduce the concept of anonymous Decls * Primitive Hello, World with inline asm works * There is still an unsolved problem of how to manage ZIR instructions memory when generating from AST. Currently it leaks. --- lib/std/zig.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'lib/std/zig.zig') diff --git a/lib/std/zig.zig b/lib/std/zig.zig index bb4f955797..87960d4321 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -1,4 +1,6 @@ +const std = @import("std.zig"); const tokenizer = @import("zig/tokenizer.zig"); + pub const Token = tokenizer.Token; pub const Tokenizer = tokenizer.Tokenizer; pub const parse = @import("zig/parse.zig").parse; @@ -9,6 +11,21 @@ pub const ast = @import("zig/ast.zig"); pub const system = @import("zig/system.zig"); pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; +pub const SrcHash = [16]u8; + +/// If the source is small enough, it is used directly as the hash. +/// If it is long, blake3 hash is computed. +pub fn hashSrc(src: []const u8) SrcHash { + var out: SrcHash = undefined; + if (src.len <= SrcHash.len) { + std.mem.copy(u8, &out, src); + std.mem.set(u8, out[src.len..], 0); + } else { + std.crypto.Blake3.hash(src, &out); + } + return out; +} + pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } { var line: usize = 0; var column: usize = 0; -- cgit v1.2.3 From 20b4a2cf2cded8904a57714ed2b90c857f12c6b1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2020 21:28:42 -0400 Subject: self-hosted: add compare output test for new AST->ZIR code --- lib/std/zig.zig | 21 +++ src-self-hosted/main.zig | 19 +-- src-self-hosted/test.zig | 295 +++++++++++++++++++---------------------- test/stage2/compare_output.zig | 137 ++++++++++++++++--- test/stage2/zir.zig | 200 ++++++++++++++-------------- 5 files changed, 372 insertions(+), 300 deletions(-) (limited to 'lib/std/zig.zig') diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 87960d4321..841827cc19 100644 --- a/lib/std/zig.zig +++ b/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()); } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index aa5a56010c..3743b4f334 100644 --- a/src-self-hosted/main.zig +++ b/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, }; diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index a7942575d0..14804cab68 100644 --- a/src-self-hosted/test.zig +++ b/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 }, - ); } } } diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 1f289c2762..182ff8131a 100644 --- a/test/stage2/compare_output.zig +++ b/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. + \\ + ); + } } diff --git a/test/stage2/zir.zig b/test/stage2/zir.zig index 832629c6e7..673be6d99f 100644 --- a/test/stage2/zir.zig +++ b/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") + , ""); } -- cgit v1.2.3