authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-24 21:28:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-24 21:28:42-04:00
log20b4a2cf2cded8904a57714ed2b90c857f12c6b1
treeb37d1fbc232319fd4e6e358183c80f1aa42f09ca
parent5aa3f56773f4b06629184a1e3753c3132b18e0bd

self-hosted: add compare output test for new AST->ZIR code


5 files changed, 372 insertions(+), 300 deletions(-)

lib/std/zig.zig+21
...@@ -43,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi...@@ -43,6 +43,27 @@ pub fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usi
43 return .{ .line = line, .column = column };43 return .{ .line = line, .column = column };
44}44}
4545
46/// Returns the standard file system basename of a binary generated by the Zig compiler.
47pub fn binNameAlloc(
48 allocator: *std.mem.Allocator,
49 root_name: []const u8,
50 target: std.Target,
51 output_mode: std.builtin.OutputMode,
52 link_mode: ?std.builtin.LinkMode,
53) error{OutOfMemory}![]u8 {
54 switch (output_mode) {
55 .Exe => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.exeFileExt() }),
56 .Lib => {
57 const suffix = switch (link_mode orelse .Static) {
58 .Static => target.staticLibSuffix(),
59 .Dynamic => target.dynamicLibSuffix(),
60 };
61 return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
62 },
63 .Obj => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.oFileExt() }),
64 }
65}
66
46test "" {67test "" {
47 @import("std").meta.refAllDecls(@This());68 @import("std").meta.refAllDecls(@This());
48}69}
src-self-hosted/main.zig+2-17
...@@ -50,8 +50,7 @@ pub fn log(...@@ -50,8 +50,7 @@ pub fn log(
50 const scope_prefix = "(" ++ switch (scope) {50 const scope_prefix = "(" ++ switch (scope) {
51 // Uncomment to hide logs51 // Uncomment to hide logs
52 //.compiler,52 //.compiler,
53 .link,53 .link => return,
54 => return,
5554
56 else => @tagName(scope),55 else => @tagName(scope),
57 } ++ "): ";56 } ++ "): ";
...@@ -431,21 +430,7 @@ fn buildOutputType(...@@ -431,21 +430,7 @@ fn buildOutputType(
431 std.debug.warn("-fno-emit-bin not supported yet", .{});430 std.debug.warn("-fno-emit-bin not supported yet", .{});
432 process.exit(1);431 process.exit(1);
433 },432 },
434 .yes_default_path => switch (output_mode) {433 .yes_default_path => try std.zig.binNameAlloc(arena, root_name, target_info.target, output_mode, link_mode),
435 .Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
436 .Lib => blk: {
437 const suffix = switch (link_mode orelse .Static) {
438 .Static => target_info.target.staticLibSuffix(),
439 .Dynamic => target_info.target.dynamicLibSuffix(),
440 };
441 break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{
442 target_info.target.libPrefix(),
443 root_name,
444 suffix,
445 });
446 },
447 .Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }),
448 },
449 .yes => |p| p,434 .yes => |p| p,
450 };435 };
451436
src-self-hosted/test.zig+138-157
...@@ -21,32 +21,7 @@ const ErrorMsg = struct {...@@ -21,32 +21,7 @@ const ErrorMsg = struct {
21};21};
2222
23pub const TestContext = struct {23pub const TestContext = struct {
24 // TODO: remove these. They are deprecated.24 zir_cases: std.ArrayList(Case),
25 zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase),
26
27 /// TODO: find a way to treat cases as individual tests (shouldn't show "1 test passed" if there are 200 cases)
28 zir_cases: std.ArrayList(ZIRCase),
29
30 // TODO: remove
31 pub const ZIRCompareOutputCase = struct {
32 name: []const u8,
33 src_list: []const []const u8,
34 expected_stdout_list: []const []const u8,
35 };
36
37 pub const ZIRUpdateType = enum {
38 /// A transformation update transforms the input ZIR and tests against
39 /// the expected output
40 Transformation,
41 /// An error update attempts to compile bad code, and ensures that it
42 /// fails to compile, and for the expected reasons
43 Error,
44 /// An execution update compiles and runs the input ZIR, feeding in
45 /// provided input and ensuring that the outputs match what is expected
46 Execution,
47 /// A compilation update checks that the ZIR compiles without any issues
48 Compiles,
49 };
5025
51 pub const ZIRUpdate = struct {26 pub const ZIRUpdate = struct {
52 /// The input to the current update. We simulate an incremental update27 /// The input to the current update. We simulate an incremental update
...@@ -57,58 +32,55 @@ pub const TestContext = struct {...@@ -57,58 +32,55 @@ pub const TestContext = struct {
57 /// you can keep it mostly consistent, with small changes, testing the32 /// you can keep it mostly consistent, with small changes, testing the
58 /// effects of the incremental compilation.33 /// effects of the incremental compilation.
59 src: [:0]const u8,34 src: [:0]const u8,
60 case: union(ZIRUpdateType) {35 case: union(enum) {
61 /// The expected output ZIR36 /// A transformation update transforms the input ZIR and tests against
37 /// the expected output ZIR.
62 Transformation: [:0]const u8,38 Transformation: [:0]const u8,
39 /// An error update attempts to compile bad code, and ensures that it
40 /// fails to compile, and for the expected reasons.
63 /// A slice containing the expected errors *in sequential order*.41 /// A slice containing the expected errors *in sequential order*.
64 Error: []const ErrorMsg,42 Error: []const ErrorMsg,
6543 /// An execution update compiles and runs the input ZIR, feeding in
66 /// Input to feed to the program, and expected outputs.44 /// provided input and ensuring that the stdout match what is expected.
67 ///45 Execution: []const u8,
68 /// If stdout, stderr, and exit_code are all null, addZIRCase will
69 /// discard the test. To test for successful compilation, use a
70 /// dedicated Compile update instead.
71 Execution: struct {
72 stdin: ?[]const u8,
73 stdout: ?[]const u8,
74 stderr: ?[]const u8,
75 exit_code: ?u8,
76 },
77 /// A Compiles test checks only that compilation of the given ZIR
78 /// succeeds. To test outputs, use an Execution test. It is good to
79 /// use a Compiles test before an Execution, as the overhead should
80 /// be low (due to incremental compilation) and TODO: provide a way
81 /// to check changed / new / etc decls in testing mode
82 /// (usingnamespace a debug info struct with a comptime flag?)
83 Compiles: void,
84 },46 },
85 };47 };
8648
87 /// A ZIRCase consists of a set of *updates*. A update can transform ZIR,49 /// A Case consists of a set of *updates*. A update can transform ZIR,
88 /// compile it, ensure that compilation fails, and more. The same Module is50 /// compile it, ensure that compilation fails, and more. The same Module is
89 /// used for each update, so each update's source is treated as a single file51 /// used for each update, so each update's source is treated as a single file
90 /// being updated by the test harness and incrementally compiled.52 /// being updated by the test harness and incrementally compiled.
91 pub const ZIRCase = struct {53 pub const Case = struct {
92 name: []const u8,54 name: []const u8,
93 /// The platform the ZIR targets. For non-native platforms, an emulator55 /// The platform the ZIR targets. For non-native platforms, an emulator
94 /// such as QEMU is required for tests to complete.56 /// such as QEMU is required for tests to complete.
95 target: std.zig.CrossTarget,57 target: std.zig.CrossTarget,
96 updates: std.ArrayList(ZIRUpdate),58 updates: std.ArrayList(ZIRUpdate),
59 output_mode: std.builtin.OutputMode,
60 /// Either ".zir" or ".zig"
61 extension: [4]u8,
9762
98 /// Adds a subcase in which the module is updated with new ZIR, and the63 /// Adds a subcase in which the module is updated with new ZIR, and the
99 /// resulting ZIR is validated.64 /// resulting ZIR is validated.
100 pub fn addTransform(self: *ZIRCase, src: [:0]const u8, result: [:0]const u8) void {65 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
101 self.updates.append(.{66 self.updates.append(.{
102 .src = src,67 .src = src,
103 .case = .{ .Transformation = result },68 .case = .{ .Transformation = result },
104 }) catch unreachable;69 }) catch unreachable;
105 }70 }
10671
72 pub fn addCompareOutput(self: *Case, src: [:0]const u8, result: []const u8) void {
73 self.updates.append(.{
74 .src = src,
75 .case = .{ .Execution = result },
76 }) catch unreachable;
77 }
78
107 /// Adds a subcase in which the module is updated with invalid ZIR, and79 /// Adds a subcase in which the module is updated with invalid ZIR, and
108 /// ensures that compilation fails for the expected reasons.80 /// ensures that compilation fails for the expected reasons.
109 ///81 ///
110 /// Errors must be specified in sequential order.82 /// Errors must be specified in sequential order.
111 pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void {83 pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {
112 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;84 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
113 for (errors) |e, i| {85 for (errors) |e, i| {
114 if (e[0] != ':') {86 if (e[0] != ':') {
...@@ -146,15 +118,65 @@ pub const TestContext = struct {...@@ -146,15 +118,65 @@ pub const TestContext = struct {
146 }118 }
147 };119 };
148120
149 pub fn addZIRMulti(121 pub fn addExeZIR(
122 ctx: *TestContext,
123 name: []const u8,
124 target: std.zig.CrossTarget,
125 ) *Case {
126 const case = Case{
127 .name = name,
128 .target = target,
129 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
130 .output_mode = .Exe,
131 .extension = ".zir".*,
132 };
133 ctx.zir_cases.append(case) catch unreachable;
134 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
135 }
136
137 pub fn addObjZIR(
138 ctx: *TestContext,
139 name: []const u8,
140 target: std.zig.CrossTarget,
141 ) *Case {
142 const case = Case{
143 .name = name,
144 .target = target,
145 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
146 .output_mode = .Obj,
147 .extension = ".zir".*,
148 };
149 ctx.zir_cases.append(case) catch unreachable;
150 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
151 }
152
153 pub fn addExe(
150 ctx: *TestContext,154 ctx: *TestContext,
151 name: []const u8,155 name: []const u8,
152 target: std.zig.CrossTarget,156 target: std.zig.CrossTarget,
153 ) *ZIRCase {157 ) *Case {
154 const case = ZIRCase{158 const case = Case{
155 .name = name,159 .name = name,
156 .target = target,160 .target = target,
157 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),161 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
162 .output_mode = .Exe,
163 .extension = ".zig".*,
164 };
165 ctx.zir_cases.append(case) catch unreachable;
166 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
167 }
168
169 pub fn addObj(
170 ctx: *TestContext,
171 name: []const u8,
172 target: std.zig.CrossTarget,
173 ) *Case {
174 const case = Case{
175 .name = name,
176 .target = target,
177 .updates = std.ArrayList(ZIRUpdate).init(ctx.zir_cases.allocator),
178 .output_mode = .Obj,
179 .extension = ".zig".*,
158 };180 };
159 ctx.zir_cases.append(case) catch unreachable;181 ctx.zir_cases.append(case) catch unreachable;
160 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];182 return &ctx.zir_cases.items[ctx.zir_cases.items.len - 1];
...@@ -163,14 +185,21 @@ pub const TestContext = struct {...@@ -163,14 +185,21 @@ pub const TestContext = struct {
163 pub fn addZIRCompareOutput(185 pub fn addZIRCompareOutput(
164 ctx: *TestContext,186 ctx: *TestContext,
165 name: []const u8,187 name: []const u8,
166 src_list: []const []const u8,188 src: [:0]const u8,
167 expected_stdout_list: []const []const u8,189 expected_stdout: []const u8,
168 ) void {190 ) void {
169 ctx.zir_cmp_output_cases.append(.{191 var c = ctx.addExeZIR(name, .{});
170 .name = name,192 c.addCompareOutput(src, expected_stdout);
171 .src_list = src_list,193 }
172 .expected_stdout_list = expected_stdout_list,194
173 }) catch unreachable;195 pub fn addCompareOutput(
196 ctx: *TestContext,
197 name: []const u8,
198 src: [:0]const u8,
199 expected_stdout: []const u8,
200 ) void {
201 var c = ctx.addExe(name, .{});
202 c.addCompareOutput(src, expected_stdout);
174 }203 }
175204
176 pub fn addZIRTransform(205 pub fn addZIRTransform(
...@@ -180,7 +209,7 @@ pub const TestContext = struct {...@@ -180,7 +209,7 @@ pub const TestContext = struct {
180 src: [:0]const u8,209 src: [:0]const u8,
181 result: [:0]const u8,210 result: [:0]const u8,
182 ) void {211 ) void {
183 var c = ctx.addZIRMulti(name, target);212 var c = ctx.addObjZIR(name, target);
184 c.addTransform(src, result);213 c.addTransform(src, result);
185 }214 }
186215
...@@ -191,20 +220,18 @@ pub const TestContext = struct {...@@ -191,20 +220,18 @@ pub const TestContext = struct {
191 src: [:0]const u8,220 src: [:0]const u8,
192 expected_errors: []const []const u8,221 expected_errors: []const []const u8,
193 ) void {222 ) void {
194 var c = ctx.addZIRMulti(name, target);223 var c = ctx.addObjZIR(name, target);
195 c.addError(src, expected_errors);224 c.addError(src, expected_errors);
196 }225 }
197226
198 fn init() TestContext {227 fn init() TestContext {
199 const allocator = std.heap.page_allocator;228 const allocator = std.heap.page_allocator;
200 return .{229 return .{
201 .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(allocator),230 .zir_cases = std.ArrayList(Case).init(allocator),
202 .zir_cases = std.ArrayList(ZIRCase).init(allocator),
203 };231 };
204 }232 }
205233
206 fn deinit(self: *TestContext) void {234 fn deinit(self: *TestContext) void {
207 self.zir_cmp_output_cases.deinit();
208 for (self.zir_cases.items) |c| {235 for (self.zir_cases.items) |c| {
209 for (c.updates.items) |u| {236 for (c.updates.items) |u| {
210 if (u.case == .Error) {237 if (u.case == .Error) {
...@@ -235,34 +262,24 @@ pub const TestContext = struct {...@@ -235,34 +262,24 @@ pub const TestContext = struct {
235 progress.refresh();262 progress.refresh();
236263
237 const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);264 const info = try std.zig.system.NativeTargetInfo.detect(std.testing.allocator, case.target);
238 try self.runOneZIRCase(std.testing.allocator, &prg_node, case, info.target);265 try self.runOneCase(std.testing.allocator, &prg_node, case, info.target);
239 try std.testing.allocator_instance.validate();
240 }
241
242 // TODO: wipe the rest of this function
243 for (self.zir_cmp_output_cases.items) |case| {
244 std.testing.base_allocator_instance.reset();
245
246 var prg_node = root_node.start(case.name, case.src_list.len);
247 prg_node.activate();
248 defer prg_node.end();
249
250 // So that we can see which test case failed when the leak checker goes off.
251 progress.refresh();
252
253 try self.runOneZIRCmpOutputCase(std.testing.allocator, &prg_node, case, native_info.target);
254 try std.testing.allocator_instance.validate();266 try std.testing.allocator_instance.validate();
255 }267 }
256 }268 }
257269
258 fn runOneZIRCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: ZIRCase, target: std.Target) !void {270 fn runOneCase(self: *TestContext, allocator: *Allocator, prg_node: *std.Progress.Node, case: Case, target: std.Target) !void {
259 var tmp = std.testing.tmpDir(.{});271 var tmp = std.testing.tmpDir(.{});
260 defer tmp.cleanup();272 defer tmp.cleanup();
261273
262 const tmp_src_path = "test_case.zir";274 const root_name = "test_case";
275 const tmp_src_path = try std.fmt.allocPrint(allocator, "{}{}", .{ root_name, case.extension });
276 defer allocator.free(tmp_src_path);
263 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);277 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);
264 defer root_pkg.destroy();278 defer root_pkg.destroy();
265279
280 const bin_name = try std.zig.binNameAlloc(allocator, root_name, target, case.output_mode, null);
281 defer allocator.free(bin_name);
282
266 var module = try Module.init(allocator, .{283 var module = try Module.init(allocator, .{
267 .target = target,284 .target = target,
268 // This is an Executable, as opposed to e.g. a *library*. This does285 // This is an Executable, as opposed to e.g. a *library*. This does
...@@ -271,17 +288,17 @@ pub const TestContext = struct {...@@ -271,17 +288,17 @@ pub const TestContext = struct {
271 // TODO: support tests for object file building, and library builds288 // TODO: support tests for object file building, and library builds
272 // and linking. This will require a rework to support multi-file289 // and linking. This will require a rework to support multi-file
273 // tests.290 // tests.
274 .output_mode = .Obj,291 .output_mode = case.output_mode,
275 // TODO: support testing optimizations292 // TODO: support testing optimizations
276 .optimize_mode = .Debug,293 .optimize_mode = .Debug,
277 .bin_file_dir = tmp.dir,294 .bin_file_dir = tmp.dir,
278 .bin_file_path = "test_case.o",295 .bin_file_path = bin_name,
279 .root_pkg = root_pkg,296 .root_pkg = root_pkg,
280 .keep_source_files_loaded = true,297 .keep_source_files_loaded = true,
281 });298 });
282 defer module.deinit();299 defer module.deinit();
283300
284 for (case.updates.items) |update| {301 for (case.updates.items) |update, update_index| {
285 var update_node = prg_node.start("update", 4);302 var update_node = prg_node.start("update", 4);
286 update_node.activate();303 update_node.activate();
287 defer update_node.end();304 defer update_node.end();
...@@ -293,6 +310,7 @@ pub const TestContext = struct {...@@ -293,6 +310,7 @@ pub const TestContext = struct {
293310
294 var module_node = update_node.start("parse/analysis/codegen", null);311 var module_node = update_node.start("parse/analysis/codegen", null);
295 module_node.activate();312 module_node.activate();
313 try module.makeBinFileWritable();
296 try module.update();314 try module.update();
297 module_node.end();315 module_node.end();
298316
...@@ -341,78 +359,41 @@ pub const TestContext = struct {...@@ -341,78 +359,41 @@ pub const TestContext = struct {
341 }359 }
342 }360 }
343 },361 },
344362 .Execution => |expected_stdout| {
345 else => return error.Unimplemented,363 var exec_result = x: {
346 }364 var exec_node = update_node.start("execute", null);
347 }365 exec_node.activate();
348 }366 defer exec_node.end();
349367
350 fn runOneZIRCmpOutputCase(368 try module.makeBinFileExecutable();
351 self: *TestContext,369
352 allocator: *Allocator,370 const exe_path = try std.fmt.allocPrint(allocator, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});
353 prg_node: *std.Progress.Node,371 defer allocator.free(exe_path);
354 case: ZIRCompareOutputCase,372
355 target: std.Target,373 break :x try std.ChildProcess.exec(.{
356 ) !void {374 .allocator = allocator,
357 var tmp = std.testing.tmpDir(.{});375 .argv = &[_][]const u8{exe_path},
358 defer tmp.cleanup();376 .cwd_dir = tmp.dir,
359377 });
360 const tmp_src_path = "test-case.zir";378 };
361 const root_pkg = try Package.create(allocator, tmp.dir, ".", tmp_src_path);379 defer allocator.free(exec_result.stdout);
362 defer root_pkg.destroy();380 defer allocator.free(exec_result.stderr);
363381 switch (exec_result.term) {
364 var module = try Module.init(allocator, .{382 .Exited => |code| {
365 .target = target,383 if (code != 0) {
366 .output_mode = .Exe,384 std.debug.warn("elf file exited with code {}\n", .{code});
367 .optimize_mode = .Debug,385 return error.BinaryBadExitCode;
368 .bin_file_dir = tmp.dir,386 }
369 .bin_file_path = "a.out",387 },
370 .root_pkg = root_pkg,388 else => return error.BinaryCrashed,
371 });389 }
372 defer module.deinit();390 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
373391 std.debug.panic(
374 for (case.src_list) |source, i| {392 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
375 var src_node = prg_node.start("update", 2);393 .{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
376 src_node.activate();394 );
377 defer src_node.end();
378
379 try tmp.dir.writeFile(tmp_src_path, source);
380
381 var update_node = src_node.start("parse,analysis,codegen", null);
382 update_node.activate();
383 try module.makeBinFileWritable();
384 try module.update();
385 update_node.end();
386
387 var exec_result = x: {
388 var exec_node = src_node.start("execute", null);
389 exec_node.activate();
390 defer exec_node.end();
391
392 try module.makeBinFileExecutable();
393 break :x try std.ChildProcess.exec(.{
394 .allocator = allocator,
395 .argv = &[_][]const u8{"./a.out"},
396 .cwd_dir = tmp.dir,
397 });
398 };
399 defer allocator.free(exec_result.stdout);
400 defer allocator.free(exec_result.stderr);
401 switch (exec_result.term) {
402 .Exited => |code| {
403 if (code != 0) {
404 std.debug.warn("elf file exited with code {}\n", .{code});
405 return error.BinaryBadExitCode;
406 }395 }
407 },396 },
408 else => return error.BinaryCrashed,
409 }
410 const expected_stdout = case.expected_stdout_list[i];
411 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {
412 std.debug.panic(
413 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
414 .{ i, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
415 );
416 }397 }
417 }398 }
418 }399 }
test/stage2/compare_output.zig+115-22
...@@ -1,28 +1,121 @@...@@ -1,28 +1,121 @@
1const std = @import("std");1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3// self-hosted does not yet support PE executable files / COFF object files
4// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
5const linux_x64 = std.zig.CrossTarget{
6 .cpu_arch = .x86_64,
7 .os_tag = .linux,
8};
39
4pub fn addCases(ctx: *TestContext) !void {10pub fn addCases(ctx: *TestContext) !void {
5 // TODO: re-enable these tests.11 if (std.Target.current.os.tag != .linux or
6 // https://github.com/ziglang/zig/issues/136412 std.Target.current.cpu.arch != .x86_64)
13 {
14 // TODO implement self-hosted PE (.exe file) linking
15 // TODO implement more ZIR so we don't depend on x86_64-linux
16 return;
17 }
718
8 //// hello world19 {
9 //try ctx.testCompareOutputLibC(20 var case = ctx.addExe("hello world with updates", linux_x64);
10 // \\extern fn puts([*]const u8) void;21 // Regular old hello world
11 // \\pub export fn main() c_int {22 case.addCompareOutput(
12 // \\ puts("Hello, world!");23 \\export fn _start() noreturn {
13 // \\ return 0;24 \\ print();
14 // \\}25 \\
15 //, "Hello, world!" ++ std.cstr.line_sep);26 \\ exit();
1627 \\}
17 //// function calling another function28 \\
18 //try ctx.testCompareOutputLibC(29 \\fn print() void {
19 // \\extern fn puts(s: [*]const u8) void;30 \\ asm volatile ("syscall"
20 // \\pub export fn main() c_int {31 \\ :
21 // \\ return foo("OK");32 \\ : [number] "{rax}" (1),
22 // \\}33 \\ [arg1] "{rdi}" (1),
23 // \\fn foo(s: [*]const u8) c_int {34 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
24 // \\ puts(s);35 \\ [arg3] "{rdx}" (14)
25 // \\ return 0;36 \\ : "rcx", "r11", "memory"
26 // \\}37 \\ );
27 //, "OK" ++ std.cstr.line_sep);38 \\ return;
39 \\}
40 \\
41 \\fn exit() noreturn {
42 \\ asm volatile ("syscall"
43 \\ :
44 \\ : [number] "{rax}" (231),
45 \\ [arg1] "{rdi}" (0)
46 \\ : "rcx", "r11", "memory"
47 \\ );
48 \\ unreachable;
49 \\}
50 ,
51 "Hello, World!\n",
52 );
53 // Now change the message only
54 case.addCompareOutput(
55 \\export fn _start() noreturn {
56 \\ print();
57 \\
58 \\ exit();
59 \\}
60 \\
61 \\fn print() void {
62 \\ asm volatile ("syscall"
63 \\ :
64 \\ : [number] "{rax}" (1),
65 \\ [arg1] "{rdi}" (1),
66 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
67 \\ [arg3] "{rdx}" (104)
68 \\ : "rcx", "r11", "memory"
69 \\ );
70 \\ return;
71 \\}
72 \\
73 \\fn exit() noreturn {
74 \\ asm volatile ("syscall"
75 \\ :
76 \\ : [number] "{rax}" (231),
77 \\ [arg1] "{rdi}" (0)
78 \\ : "rcx", "r11", "memory"
79 \\ );
80 \\ unreachable;
81 \\}
82 ,
83 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
84 );
85 // Now we print it twice.
86 case.addCompareOutput(
87 \\export fn _start() noreturn {
88 \\ print();
89 \\ print();
90 \\
91 \\ exit();
92 \\}
93 \\
94 \\fn print() void {
95 \\ asm volatile ("syscall"
96 \\ :
97 \\ : [number] "{rax}" (1),
98 \\ [arg1] "{rdi}" (1),
99 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
100 \\ [arg3] "{rdx}" (104)
101 \\ : "rcx", "r11", "memory"
102 \\ );
103 \\ return;
104 \\}
105 \\
106 \\fn exit() noreturn {
107 \\ asm volatile ("syscall"
108 \\ :
109 \\ : [number] "{rax}" (231),
110 \\ [arg1] "{rdi}" (0)
111 \\ : "rcx", "r11", "memory"
112 \\ );
113 \\ unreachable;
114 \\}
115 ,
116 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
117 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
118 \\
119 );
120 }
28}121}
test/stage2/zir.zig+96-104
...@@ -86,7 +86,7 @@ pub fn addCases(ctx: *TestContext) void {...@@ -86,7 +86,7 @@ pub fn addCases(ctx: *TestContext) void {
86 );86 );
8787
88 {88 {
89 var case = ctx.addZIRMulti("reference cycle with compile error in the cycle", linux_x64);89 var case = ctx.addObjZIR("reference cycle with compile error in the cycle", linux_x64);
90 case.addTransform(90 case.addTransform(
91 \\@void = primitive(void)91 \\@void = primitive(void)
92 \\@fnty = fntype([], @void, cc=C)92 \\@fnty = fntype([], @void, cc=C)
...@@ -207,109 +207,101 @@ pub fn addCases(ctx: *TestContext) void {...@@ -207,109 +207,101 @@ pub fn addCases(ctx: *TestContext) void {
207 return;207 return;
208 }208 }
209209
210 ctx.addZIRCompareOutput(210 ctx.addZIRCompareOutput("hello world ZIR",
211 "hello world ZIR",211 \\@noreturn = primitive(noreturn)
212 &[_][]const u8{212 \\@void = primitive(void)
213 \\@noreturn = primitive(noreturn)213 \\@usize = primitive(usize)
214 \\@void = primitive(void)214 \\@0 = int(0)
215 \\@usize = primitive(usize)215 \\@1 = int(1)
216 \\@0 = int(0)216 \\@2 = int(2)
217 \\@1 = int(1)217 \\@3 = int(3)
218 \\@2 = int(2)218 \\
219 \\@3 = int(3)219 \\@msg = str("Hello, world!\n")
220 \\220 \\
221 \\@msg = str("Hello, world!\n")221 \\@start_fnty = fntype([], @noreturn, cc=Naked)
222 \\222 \\@start = fn(@start_fnty, {
223 \\@start_fnty = fntype([], @noreturn, cc=Naked)223 \\ %SYS_exit_group = int(231)
224 \\@start = fn(@start_fnty, {224 \\ %exit_code = as(@usize, @0)
225 \\ %SYS_exit_group = int(231)225 \\
226 \\ %exit_code = as(@usize, @0)226 \\ %syscall = str("syscall")
227 \\227 \\ %sysoutreg = str("={rax}")
228 \\ %syscall = str("syscall")228 \\ %rax = str("{rax}")
229 \\ %sysoutreg = str("={rax}")229 \\ %rdi = str("{rdi}")
230 \\ %rax = str("{rax}")230 \\ %rcx = str("rcx")
231 \\ %rdi = str("{rdi}")231 \\ %rdx = str("{rdx}")
232 \\ %rcx = str("rcx")232 \\ %rsi = str("{rsi}")
233 \\ %rdx = str("{rdx}")233 \\ %r11 = str("r11")
234 \\ %rsi = str("{rsi}")234 \\ %memory = str("memory")
235 \\ %r11 = str("r11")235 \\
236 \\ %memory = str("memory")236 \\ %SYS_write = as(@usize, @1)
237 \\237 \\ %STDOUT_FILENO = as(@usize, @1)
238 \\ %SYS_write = as(@usize, @1)238 \\
239 \\ %STDOUT_FILENO = as(@usize, @1)239 \\ %msg_addr = ptrtoint(@msg)
240 \\240 \\
241 \\ %msg_addr = ptrtoint(@msg)241 \\ %len_name = str("len")
242 \\242 \\ %msg_len_ptr = fieldptr(@msg, %len_name)
243 \\ %len_name = str("len")243 \\ %msg_len = deref(%msg_len_ptr)
244 \\ %msg_len_ptr = fieldptr(@msg, %len_name)244 \\ %rc_write = asm(%syscall, @usize,
245 \\ %msg_len = deref(%msg_len_ptr)245 \\ volatile=1,
246 \\ %rc_write = asm(%syscall, @usize,246 \\ output=%sysoutreg,
247 \\ volatile=1,247 \\ inputs=[%rax, %rdi, %rsi, %rdx],
248 \\ output=%sysoutreg,248 \\ clobbers=[%rcx, %r11, %memory],
249 \\ inputs=[%rax, %rdi, %rsi, %rdx],249 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])
250 \\ clobbers=[%rcx, %r11, %memory],250 \\
251 \\ args=[%SYS_write, %STDOUT_FILENO, %msg_addr, %msg_len])251 \\ %rc_exit = asm(%syscall, @usize,
252 \\252 \\ volatile=1,
253 \\ %rc_exit = asm(%syscall, @usize,253 \\ output=%sysoutreg,
254 \\ volatile=1,254 \\ inputs=[%rax, %rdi],
255 \\ output=%sysoutreg,255 \\ clobbers=[%rcx, %r11, %memory],
256 \\ inputs=[%rax, %rdi],256 \\ args=[%SYS_exit_group, %exit_code])
257 \\ clobbers=[%rcx, %r11, %memory],257 \\
258 \\ args=[%SYS_exit_group, %exit_code])258 \\ %99 = unreachable()
259 \\259 \\});
260 \\ %99 = unreachable()260 \\
261 \\});261 \\@9 = str("_start")
262 \\262 \\@11 = export(@9, "start")
263 \\@9 = str("_start")263 ,
264 \\@11 = export(@9, "start")264 \\Hello, world!
265 },265 \\
266 &[_][]const u8{
267 \\Hello, world!
268 \\
269 },
270 );266 );
271267
272 ctx.addZIRCompareOutput(268 ctx.addZIRCompareOutput("function call with no args no return value",
273 "function call with no args no return value",269 \\@noreturn = primitive(noreturn)
274 &[_][]const u8{270 \\@void = primitive(void)
275 \\@noreturn = primitive(noreturn)271 \\@usize = primitive(usize)
276 \\@void = primitive(void)272 \\@0 = int(0)
277 \\@usize = primitive(usize)273 \\@1 = int(1)
278 \\@0 = int(0)274 \\@2 = int(2)
279 \\@1 = int(1)275 \\@3 = int(3)
280 \\@2 = int(2)276 \\
281 \\@3 = int(3)277 \\@exit0_fnty = fntype([], @noreturn)
282 \\278 \\@exit0 = fn(@exit0_fnty, {
283 \\@exit0_fnty = fntype([], @noreturn)279 \\ %SYS_exit_group = int(231)
284 \\@exit0 = fn(@exit0_fnty, {280 \\ %exit_code = as(@usize, @0)
285 \\ %SYS_exit_group = int(231)281 \\
286 \\ %exit_code = as(@usize, @0)282 \\ %syscall = str("syscall")
287 \\283 \\ %sysoutreg = str("={rax}")
288 \\ %syscall = str("syscall")284 \\ %rax = str("{rax}")
289 \\ %sysoutreg = str("={rax}")285 \\ %rdi = str("{rdi}")
290 \\ %rax = str("{rax}")286 \\ %rcx = str("rcx")
291 \\ %rdi = str("{rdi}")287 \\ %r11 = str("r11")
292 \\ %rcx = str("rcx")288 \\ %memory = str("memory")
293 \\ %r11 = str("r11")289 \\
294 \\ %memory = str("memory")290 \\ %rc = asm(%syscall, @usize,
295 \\291 \\ volatile=1,
296 \\ %rc = asm(%syscall, @usize,292 \\ output=%sysoutreg,
297 \\ volatile=1,293 \\ inputs=[%rax, %rdi],
298 \\ output=%sysoutreg,294 \\ clobbers=[%rcx, %r11, %memory],
299 \\ inputs=[%rax, %rdi],295 \\ args=[%SYS_exit_group, %exit_code])
300 \\ clobbers=[%rcx, %r11, %memory],296 \\
301 \\ args=[%SYS_exit_group, %exit_code])297 \\ %99 = unreachable()
302 \\298 \\});
303 \\ %99 = unreachable()299 \\
304 \\});300 \\@start_fnty = fntype([], @noreturn, cc=Naked)
305 \\301 \\@start = fn(@start_fnty, {
306 \\@start_fnty = fntype([], @noreturn, cc=Naked)302 \\ %0 = call(@exit0, [])
307 \\@start = fn(@start_fnty, {303 \\})
308 \\ %0 = call(@exit0, [])304 \\@9 = str("_start")
309 \\})305 \\@11 = export(@9, "start")
310 \\@9 = str("_start")306 , "");
311 \\@11 = export(@9, "start")
312 },
313 &[_][]const u8{""},
314 );
315}307}