mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
self-hosted: add compare output test for new AST->ZIR code
This commit is contained in:
parent
5aa3f56773
commit
20b4a2cf2c
@ -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());
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -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,
|
||||
) *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 = ".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,
|
||||
) *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 {
|
||||
}
|
||||
}
|
||||
},
|
||||
.Execution => |expected_stdout| {
|
||||
var exec_result = x: {
|
||||
var exec_node = update_node.start("execute", null);
|
||||
exec_node.activate();
|
||||
defer exec_node.end();
|
||||
|
||||
else => return error.Unimplemented,
|
||||
}
|
||||
}
|
||||
}
|
||||
try module.makeBinFileExecutable();
|
||||
|
||||
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 exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
|
||||
defer allocator.free(exe_path);
|
||||
|
||||
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;
|
||||
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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
\\
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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")
|
||||
, "");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user