From 1d202008d8008681988effdf25be2c6a753cf067 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 29 Apr 2020 19:38:45 -0400 Subject: [PATCH] add ZIR transform test case --- src-self-hosted/test.zig | 96 ++++++++++++++++++++++++++++++++++++---- test/stage2/zir.zig | 45 +++++++++++++++++++ 2 files changed, 133 insertions(+), 8 deletions(-) diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index 51d12da44..5868f9383 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -16,6 +16,7 @@ test "self-hosted" { pub const TestContext = struct { zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase), + zir_transform_cases: std.ArrayList(ZIRTransformCase), pub const ZIRCompareOutputCase = struct { name: []const u8, @@ -23,6 +24,12 @@ pub const TestContext = struct { expected_stdout: []const u8, }; + pub const ZIRTransformCase = struct { + name: []const u8, + src: [:0]const u8, + expected_zir: []const u8, + }; + pub fn addZIRCompareOutput( ctx: *TestContext, name: []const u8, @@ -36,20 +43,36 @@ pub const TestContext = struct { }) catch unreachable; } + pub fn addZIRTransform( + ctx: *TestContext, + name: []const u8, + src: [:0]const u8, + expected_zir: []const u8, + ) void { + ctx.zir_transform_cases.append(.{ + .name = name, + .src = src, + .expected_zir = expected_zir, + }) catch unreachable; + } + fn init(self: *TestContext) !void { self.* = .{ .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), + .zir_transform_cases = std.ArrayList(ZIRTransformCase).init(std.heap.page_allocator), }; } fn deinit(self: *TestContext) void { self.zir_cmp_output_cases.deinit(); + self.zir_transform_cases.deinit(); self.* = undefined; } fn run(self: *TestContext) !void { var progress = std.Progress{}; - const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len); + const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len + + self.zir_transform_cases.items.len); defer root_node.end(); const native_info = try std.zig.system.NativeTargetInfo.detect(std.heap.page_allocator, .{}); @@ -59,6 +82,11 @@ pub const TestContext = struct { try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target); try std.testing.allocator_instance.validate(); } + for (self.zir_transform_cases.items) |case| { + std.testing.base_allocator_instance.reset(); + try self.runOneZIRTransformCase(std.testing.allocator, root_node, case, native_info.target); + try std.testing.allocator_instance.validate(); + } } fn runOneZIRCmpOutputCase( @@ -93,7 +121,12 @@ pub const TestContext = struct { analyze_node.activate(); defer analyze_node.end(); - break :x try ir.analyze(allocator, zir_module, target); + break :x try ir.analyze(allocator, zir_module, .{ + .target = target, + .output_mode = .Exe, + .link_mode = .Static, + .optimize_mode = .Debug, + }); }; defer analyzed_module.deinit(allocator); if (analyzed_module.errors.len != 0) { @@ -106,12 +139,7 @@ pub const TestContext = struct { link_node.activate(); defer link_node.end(); - break :x try link.updateExecutableFilePath( - allocator, - analyzed_module, - tmp.dir, - "a.out", - ); + break :x try link.updateFilePath(allocator, analyzed_module, tmp.dir, "a.out"); }; defer link_result.deinit(allocator); if (link_result.errors.len != 0) { @@ -143,6 +171,58 @@ pub const TestContext = struct { } std.testing.expectEqualSlices(u8, case.expected_stdout, exec_result.stdout); } + + fn runOneZIRTransformCase( + self: *TestContext, + allocator: *Allocator, + root_node: *std.Progress.Node, + case: ZIRTransformCase, + target: std.Target, + ) !void { + var prg_node = root_node.start(case.name, 4); + prg_node.activate(); + defer prg_node.end(); + + var parse_node = prg_node.start("parse", null); + parse_node.activate(); + var zir_module = try ir.text.parse(allocator, case.src); + defer zir_module.deinit(allocator); + if (zir_module.errors.len != 0) { + debugPrintErrors(case.src, zir_module.errors); + return error.ParseFailure; + } + parse_node.end(); + + var analyze_node = prg_node.start("analyze", null); + analyze_node.activate(); + var analyzed_module = try ir.analyze(allocator, zir_module, .{ + .target = target, + .output_mode = .Obj, + .link_mode = .Static, + .optimize_mode = .Debug, + }); + defer analyzed_module.deinit(allocator); + if (analyzed_module.errors.len != 0) { + debugPrintErrors(case.src, analyzed_module.errors); + return error.ParseFailure; + } + analyze_node.end(); + + var emit_node = prg_node.start("emit", null); + emit_node.activate(); + var new_zir_module = try ir.text.emit_zir(allocator, analyzed_module); + defer new_zir_module.deinit(allocator); + emit_node.end(); + + var write_node = prg_node.start("write", null); + write_node.activate(); + var out_zir = std.ArrayList(u8).init(allocator); + defer out_zir.deinit(); + try new_zir_module.writeToStream(allocator, out_zir.outStream()); + write_node.end(); + + std.testing.expectEqualSlices(u8, case.expected_zir, out_zir.items); + } }; fn debugPrintErrors(src: []const u8, errors: var) void { diff --git a/test/stage2/zir.zig b/test/stage2/zir.zig index d2ea3c01f..9a65e9ab9 100644 --- a/test/stage2/zir.zig +++ b/test/stage2/zir.zig @@ -1,6 +1,51 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext; pub fn addCases(ctx: *TestContext) void { + ctx.addZIRTransform("elemptr, add, cmp, condbr, return, breakpoint", + \\@void = primitive(void) + \\@usize = primitive(usize) + \\@fnty = fntype([], @void, cc=C) + \\@0 = int(0) + \\@1 = int(1) + \\@2 = int(2) + \\@3 = int(3) + \\ + \\@entry = fn(@fnty, { + \\ %a = str("\x32\x08\x01\x0a") + \\ %eptr0 = elemptr(%a, @0) + \\ %eptr1 = elemptr(%a, @1) + \\ %eptr2 = elemptr(%a, @2) + \\ %eptr3 = elemptr(%a, @3) + \\ %v0 = deref(%eptr0) + \\ %v1 = deref(%eptr1) + \\ %v2 = deref(%eptr2) + \\ %v3 = deref(%eptr3) + \\ %x0 = add(%v0, %v1) + \\ %x1 = add(%v2, %v3) + \\ %result = add(%x0, %x1) + \\ + \\ %expected = int(69) + \\ %ok = cmp(%result, eq, %expected) + \\ %10 = condbr(%ok, { + \\ %11 = return() + \\ }, { + \\ %12 = breakpoint() + \\ }) + \\}) + \\ + \\@9 = str("entry") + \\@10 = export(@9, @entry) + , + \\@0 = primitive(void) + \\@1 = fntype([], @0, cc=C) + \\@2 = fn(@1, { + \\ %0 = return() + \\}) + \\@3 = str("entry") + \\@4 = export(@3, @2) + \\ + ); + if (@import("std").Target.current.os.tag != .linux or @import("std").Target.current.cpu.arch != .x86_64) {