Commit 1d202008d8

Andrew Kelley <andrew@ziglang.org>
2020-04-30 01:38:45
add ZIR transform test case
1 parent 751903b
Changed files (2)
src-self-hosted
test
stage2
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 {
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)
     {