| ... | @@ -16,6 +16,7 @@ test "self-hosted" { | ... | @@ -16,6 +16,7 @@ test "self-hosted" { |
| 16 | | 16 | |
| 17 | pub const TestContext = struct { | 17 | pub const TestContext = struct { |
| 18 | zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase), | 18 | zir_cmp_output_cases: std.ArrayList(ZIRCompareOutputCase), |
| | 19 | zir_transform_cases: std.ArrayList(ZIRTransformCase), |
| 19 | | 20 | |
| 20 | pub const ZIRCompareOutputCase = struct { | 21 | pub const ZIRCompareOutputCase = struct { |
| 21 | name: []const u8, | 22 | name: []const u8, |
| ... | @@ -23,6 +24,12 @@ pub const TestContext = struct { | ... | @@ -23,6 +24,12 @@ pub const TestContext = struct { |
| 23 | expected_stdout: []const u8, | 24 | expected_stdout: []const u8, |
| 24 | }; | 25 | }; |
| 25 | | 26 | |
| | 27 | pub const ZIRTransformCase = struct { |
| | 28 | name: []const u8, |
| | 29 | src: [:0]const u8, |
| | 30 | expected_zir: []const u8, |
| | 31 | }; |
| | 32 | |
| 26 | pub fn addZIRCompareOutput( | 33 | pub fn addZIRCompareOutput( |
| 27 | ctx: *TestContext, | 34 | ctx: *TestContext, |
| 28 | name: []const u8, | 35 | name: []const u8, |
| ... | @@ -36,20 +43,36 @@ pub const TestContext = struct { | ... | @@ -36,20 +43,36 @@ pub const TestContext = struct { |
| 36 | }) catch unreachable; | 43 | }) catch unreachable; |
| 37 | } | 44 | } |
| 38 | | 45 | |
| | 46 | pub fn addZIRTransform( |
| | 47 | ctx: *TestContext, |
| | 48 | name: []const u8, |
| | 49 | src: [:0]const u8, |
| | 50 | expected_zir: []const u8, |
| | 51 | ) void { |
| | 52 | ctx.zir_transform_cases.append(.{ |
| | 53 | .name = name, |
| | 54 | .src = src, |
| | 55 | .expected_zir = expected_zir, |
| | 56 | }) catch unreachable; |
| | 57 | } |
| | 58 | |
| 39 | fn init(self: *TestContext) !void { | 59 | fn init(self: *TestContext) !void { |
| 40 | self.* = .{ | 60 | self.* = .{ |
| 41 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), | 61 | .zir_cmp_output_cases = std.ArrayList(ZIRCompareOutputCase).init(std.heap.page_allocator), |
| | 62 | .zir_transform_cases = std.ArrayList(ZIRTransformCase).init(std.heap.page_allocator), |
| 42 | }; | 63 | }; |
| 43 | } | 64 | } |
| 44 | | 65 | |
| 45 | fn deinit(self: *TestContext) void { | 66 | fn deinit(self: *TestContext) void { |
| 46 | self.zir_cmp_output_cases.deinit(); | 67 | self.zir_cmp_output_cases.deinit(); |
| | 68 | self.zir_transform_cases.deinit(); |
| 47 | self.* = undefined; | 69 | self.* = undefined; |
| 48 | } | 70 | } |
| 49 | | 71 | |
| 50 | fn run(self: *TestContext) !void { | 72 | fn run(self: *TestContext) !void { |
| 51 | var progress = std.Progress{}; | 73 | var progress = std.Progress{}; |
| 52 | const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len); | 74 | const root_node = try progress.start("zir", self.zir_cmp_output_cases.items.len + |
| | 75 | self.zir_transform_cases.items.len); |
| 53 | defer root_node.end(); | 76 | defer root_node.end(); |
| 54 | | 77 | |
| 55 | const native_info = try std.zig.system.NativeTargetInfo.detect(std.heap.page_allocator, .{}); | 78 | const native_info = try std.zig.system.NativeTargetInfo.detect(std.heap.page_allocator, .{}); |
| ... | @@ -59,6 +82,11 @@ pub const TestContext = struct { | ... | @@ -59,6 +82,11 @@ pub const TestContext = struct { |
| 59 | try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target); | 82 | try self.runOneZIRCmpOutputCase(std.testing.allocator, root_node, case, native_info.target); |
| 60 | try std.testing.allocator_instance.validate(); | 83 | try std.testing.allocator_instance.validate(); |
| 61 | } | 84 | } |
| | 85 | for (self.zir_transform_cases.items) |case| { |
| | 86 | std.testing.base_allocator_instance.reset(); |
| | 87 | try self.runOneZIRTransformCase(std.testing.allocator, root_node, case, native_info.target); |
| | 88 | try std.testing.allocator_instance.validate(); |
| | 89 | } |
| 62 | } | 90 | } |
| 63 | | 91 | |
| 64 | fn runOneZIRCmpOutputCase( | 92 | fn runOneZIRCmpOutputCase( |
| ... | @@ -93,7 +121,12 @@ pub const TestContext = struct { | ... | @@ -93,7 +121,12 @@ pub const TestContext = struct { |
| 93 | analyze_node.activate(); | 121 | analyze_node.activate(); |
| 94 | defer analyze_node.end(); | 122 | defer analyze_node.end(); |
| 95 | | 123 | |
| 96 | break :x try ir.analyze(allocator, zir_module, target); | 124 | break :x try ir.analyze(allocator, zir_module, .{ |
| | 125 | .target = target, |
| | 126 | .output_mode = .Exe, |
| | 127 | .link_mode = .Static, |
| | 128 | .optimize_mode = .Debug, |
| | 129 | }); |
| 97 | }; | 130 | }; |
| 98 | defer analyzed_module.deinit(allocator); | 131 | defer analyzed_module.deinit(allocator); |
| 99 | if (analyzed_module.errors.len != 0) { | 132 | if (analyzed_module.errors.len != 0) { |
| ... | @@ -106,12 +139,7 @@ pub const TestContext = struct { | ... | @@ -106,12 +139,7 @@ pub const TestContext = struct { |
| 106 | link_node.activate(); | 139 | link_node.activate(); |
| 107 | defer link_node.end(); | 140 | defer link_node.end(); |
| 108 | | 141 | |
| 109 | break :x try link.updateExecutableFilePath( | 142 | break :x try link.updateFilePath(allocator, analyzed_module, tmp.dir, "a.out"); |
| 110 | allocator, | | |
| 111 | analyzed_module, | | |
| 112 | tmp.dir, | | |
| 113 | "a.out", | | |
| 114 | ); | | |
| 115 | }; | 143 | }; |
| 116 | defer link_result.deinit(allocator); | 144 | defer link_result.deinit(allocator); |
| 117 | if (link_result.errors.len != 0) { | 145 | if (link_result.errors.len != 0) { |
| ... | @@ -143,6 +171,58 @@ pub const TestContext = struct { | ... | @@ -143,6 +171,58 @@ pub const TestContext = struct { |
| 143 | } | 171 | } |
| 144 | std.testing.expectEqualSlices(u8, case.expected_stdout, exec_result.stdout); | 172 | std.testing.expectEqualSlices(u8, case.expected_stdout, exec_result.stdout); |
| 145 | } | 173 | } |
| | 174 | |
| | 175 | fn runOneZIRTransformCase( |
| | 176 | self: *TestContext, |
| | 177 | allocator: *Allocator, |
| | 178 | root_node: *std.Progress.Node, |
| | 179 | case: ZIRTransformCase, |
| | 180 | target: std.Target, |
| | 181 | ) !void { |
| | 182 | var prg_node = root_node.start(case.name, 4); |
| | 183 | prg_node.activate(); |
| | 184 | defer prg_node.end(); |
| | 185 | |
| | 186 | var parse_node = prg_node.start("parse", null); |
| | 187 | parse_node.activate(); |
| | 188 | var zir_module = try ir.text.parse(allocator, case.src); |
| | 189 | defer zir_module.deinit(allocator); |
| | 190 | if (zir_module.errors.len != 0) { |
| | 191 | debugPrintErrors(case.src, zir_module.errors); |
| | 192 | return error.ParseFailure; |
| | 193 | } |
| | 194 | parse_node.end(); |
| | 195 | |
| | 196 | var analyze_node = prg_node.start("analyze", null); |
| | 197 | analyze_node.activate(); |
| | 198 | var analyzed_module = try ir.analyze(allocator, zir_module, .{ |
| | 199 | .target = target, |
| | 200 | .output_mode = .Obj, |
| | 201 | .link_mode = .Static, |
| | 202 | .optimize_mode = .Debug, |
| | 203 | }); |
| | 204 | defer analyzed_module.deinit(allocator); |
| | 205 | if (analyzed_module.errors.len != 0) { |
| | 206 | debugPrintErrors(case.src, analyzed_module.errors); |
| | 207 | return error.ParseFailure; |
| | 208 | } |
| | 209 | analyze_node.end(); |
| | 210 | |
| | 211 | var emit_node = prg_node.start("emit", null); |
| | 212 | emit_node.activate(); |
| | 213 | var new_zir_module = try ir.text.emit_zir(allocator, analyzed_module); |
| | 214 | defer new_zir_module.deinit(allocator); |
| | 215 | emit_node.end(); |
| | 216 | |
| | 217 | var write_node = prg_node.start("write", null); |
| | 218 | write_node.activate(); |
| | 219 | var out_zir = std.ArrayList(u8).init(allocator); |
| | 220 | defer out_zir.deinit(); |
| | 221 | try new_zir_module.writeToStream(allocator, out_zir.outStream()); |
| | 222 | write_node.end(); |
| | 223 | |
| | 224 | std.testing.expectEqualSlices(u8, case.expected_zir, out_zir.items); |
| | 225 | } |
| 146 | }; | 226 | }; |
| 147 | | 227 | |
| 148 | fn debugPrintErrors(src: []const u8, errors: var) void { | 228 | fn debugPrintErrors(src: []const u8, errors: var) void { |