authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-10-08 01:55:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-21 10:05:30-07:00
log1157dd95714e57a699f06066ccfc7ed511ebf43f
tree69f3c45315c31aa6cd14bf77498e3d0570c7733f
parent809fcd4910552b57e0a61567fd5706719315bb22

test/llvm-ir: convert to new runner


13 files changed, 331 insertions(+), 338 deletions(-)

build.zig+4-5
......@@ -712,11 +712,6 @@ pub fn build(b: *std.Build) !void {
712712 .skip_libc = skip_libc,
713713 }));
714714 test_step.dependOn(tests.addCliTests(b));
715 if (tests.addLlvmIrTests(b, .{
716 .enable_llvm = enable_llvm,
717 .test_filters = test_filters,
718 .test_target_filters = test_target_filters,
719 })) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step);
720715
721716 try addWasiUpdateStep(b, version);
722717
......@@ -822,6 +817,10 @@ pub fn build(b: *std.Build) !void {
822817 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests");
823818 try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts);
824819 test_step.dependOn(test_incremental_step);
820
821 const test_llvm_ir_step = b.step("test-llvm-ir", "Run the LLVM IR tests");
822 try tests.addRunnerTests(b, runner, test_llvm_ir_step, "test/llvm-ir", @import("test/llvm-ir/matrix.zon"), runner_opts);
823 test_step.dependOn(test_llvm_ir_step);
825824}
826825
827826fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
lib/std/posix.zig+1-1
......@@ -797,7 +797,7 @@ pub fn dl_iterate_phdr(
797797 const dl = @import("dynamic_library.zig");
798798
799799 switch (builtin.object_format) {
800 .elf, .c => {},
800 .c, .elf, .llvmbc, .llvmir => {},
801801 else => @compileError("dl_iterate_phdr is not available for this target"),
802802 }
803803
test/Runner.zig+26-5
......@@ -917,6 +917,7 @@ fn handleCommand(
917917 .arch_os_abi = triple,
918918 .object_format = switch (backend) {
919919 .sema, .selfhosted, .llvm => null,
920 .llvmir => "llvmir",
920921 .cbe => "c",
921922 },
922923 }) catch |err| switch (err) {
......@@ -1075,7 +1076,7 @@ fn handleCommand(
10751076 ),
10761077 };
10771078 },
1078 .stdout, .exit, .gdb, .lldb => if (eb.errorMessageCount() > 0) {
1079 .stdout, .exit, .llvm, .gdb, .lldb => if (eb.errorMessageCount() > 0) {
10791080 eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) {
10801081 error.Canceled => {},
10811082 else => {},
......@@ -1146,6 +1147,7 @@ fn spawnCompiler(
11461147 .sema => try argv.append(gpa, "-fno-emit-bin"),
11471148 .selfhosted => try argv.append(gpa, "-fno-llvm"),
11481149 .llvm => try argv.append(gpa, "-fllvm"),
1150 .llvmir => try argv.append(gpa, "-ofmt=llvmir"),
11491151 .cbe => try argv.append(gpa, "-ofmt=c"),
11501152 } else try argv.appendSlice(gpa, &.{ "-I", path_buffer[0 .. (runner.args.lib_dir orelse
11511153 return runner.fail("\"--lib=path/to/lib\" arg required with cbe", .{}))
......@@ -1287,6 +1289,8 @@ const Compiler = struct {
12871289 /// Use the LLVM backend.
12881290 /// Corresponds to `-fllvm -flld`.
12891291 llvm,
1292 /// Use the LLVM backend without libLLVM.
1293 llvmir,
12901294 /// Use the C backend. The output is compiled with `zig cc`.
12911295 /// Corresponds to `-ofmt=c`.
12921296 cbe,
......@@ -1325,7 +1329,7 @@ const Compiler = struct {
13251329 return .{ .tag = header.tag, .body = body };
13261330 }
13271331
1328 const Check = enum { errors, stdout, exit, gdb, lldb };
1332 const Check = enum { errors, stdout, exit, llvm, gdb, lldb };
13291333 fn checkSuccess(
13301334 comp: *Compiler,
13311335 update: *const Update,
......@@ -1361,7 +1365,7 @@ const Compiler = struct {
13611365 var script_buffer: [512]u8 = undefined;
13621366 const script_path, const script_file, var script_fw = script: switch (check) {
13631367 .errors => return,
1364 .stdout, .exit => .{ undefined, null, undefined },
1368 .stdout, .exit, .llvm => .{ undefined, null, undefined },
13651369 .gdb => {
13661370 const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb";
13671371 argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" });
......@@ -1425,7 +1429,7 @@ const Compiler = struct {
14251429 const out_path = try std.Io.Dir.path.join(arena, &.{ out_dir_path, comp.out_name });
14261430 const bin_path = switch (comp.target.backend.?) {
14271431 .sema => return,
1428 .selfhosted, .llvm => out_path,
1432 .selfhosted, .llvm, .llvmir => out_path,
14291433 .cbe => try comp.compileC(update.src_dir, out_path),
14301434 };
14311435
......@@ -1527,6 +1531,23 @@ const Compiler = struct {
15271531 .exe = exe: switch (check) {
15281532 .errors => unreachable,
15291533 .stdout, .exit => if (use_executor) .search else .{ .file = bin_file },
1534 .llvm => {
1535 var bin_fr = bin_file.reader(io, &.{});
1536 const actual = bin_fr.interface.readAllocAll(arena, @intCast(
1537 bin_fr.getSize() catch |err| switch (err) {
1538 error.Canceled => |e| return e,
1539 else => |e| return runner.fail("unable to get size of {q}: {t}", .{ bin_path, e }),
1540 },
1541 )) catch |err| switch (switch (err) {
1542 error.OutOfMemory => |e| return e,
1543 error.EndOfStream => |e| e,
1544 error.ReadFailed => bin_fr.err.?,
1545 }) {
1546 error.Canceled => |e| return e,
1547 else => |e| return runner.fail("unable to read {q}: {t}", .{ bin_path, e }),
1548 };
1549 return update.checkMatches("LLVM IR", expected, actual);
1550 },
15301551 .gdb, .lldb => {
15311552 if (use_executor) {
15321553 if (!runner.args.quiet) std.log.warn(
......@@ -1603,7 +1624,7 @@ const Compiler = struct {
16031624 }
16041625 switch (result.term) {
16051626 .exited => |code| switch (check) {
1606 .errors => unreachable,
1627 .errors, .llvm => unreachable,
16071628 .stdout => {
16081629 if (code != 0) return update.fail(
16091630 "generated executable {q} failed with code {d}",
test/llvm-ir/allowzero created+72
......@@ -0,0 +1,72 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn entry(ptr: *allowzero i16) i16 {
8 return ptr.*;
9}
10#}
11#update "load"
12#check llvm {
13define #...@test.entry(ptr #...%0) #...#0 #...{
14#...load i16, ptr %0#...
15}
16
17#...
18attributes #0 = {#... null_pointer_is_valid #...}
19#}
20
21#write test.zig {
22export fn entry(ptr: *allowzero i16) void {
23 ptr.* = 42;
24}
25#}
26#update "store"
27#check llvm {
28define #...@test.entry(ptr #...%0) #...#0 #...{
29#...store i16 42, ptr %0#...
30}
31
32#...
33attributes #0 = {#... null_pointer_is_valid #...}
34#}
35
36#write test.zig {
37export fn entry(ptr: *allowzero i16) i16 {
38 return entry2(ptr[0..1]);
39}
40fn entry2(slice: []allowzero i16) i16 {
41 @setRuntimeSafety(false);
42 return slice[0];
43}
44#}
45#update "slice load"
46#check llvm {
47define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{
48#...load i16, ptr %#...
49}
50
51#...
52attributes #2 = {#... null_pointer_is_valid #...}
53#}
54
55#write test.zig {
56export fn entry(ptr: *allowzero i16) void {
57 entry2(ptr[0..1]);
58}
59fn entry2(slice: []allowzero i16) void {
60 @setRuntimeSafety(false);
61 slice[0] = 42;
62}
63#}
64#update "slice store"
65#check llvm {
66define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{
67#...store i16 42, ptr %#...
68}
69
70#...
71attributes #2 = {#... null_pointer_is_valid #...}
72#}
test/llvm-ir/array_to_vector created+38
......@@ -0,0 +1,38 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn entry(arr: *const [16]u8) @Vector(16, u8) {
8 return arr.*;
9}
10#}
11#update "one vector load"
12#check llvm {
13define #...<16 x i8> @test.entry(#...) #...{
14#...
15 %1 = alloca [16 x i8], align 1#...
16 %3 = load <16 x i8>, ptr %1, align 1#...
17 ret <16 x i8> %3#...
18#}
19
20#write test.zig {
21export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void {
22 const q: @Vector(16, u8) = src[0..16].*;
23 a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 });
24 b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 });
25}
26#}
27#update "feeding overlapping shuffles"
28#check llvm {
29define #...void @test.entry(ptr #...%0, ptr #...%1, #...) #...{
30#...
31 %11 = load <16 x i8>, ptr %#...
32 %12 = shufflevector <16 x i8> %11, #...
33 store <8 x i8> %12, ptr %0, align 8#...
34 %13 = shufflevector <16 x i8> %11, #...
35 store <8 x i8> %13, ptr %1, align 8#...
36 ret void#...
37}
38#}
test/llvm-ir/dead_store created+43
......@@ -0,0 +1,43 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn entry(ptr: *volatile i16) void {
8 ptr.* = 123;
9 ptr.* = 321;
10}
11#}
12#update "volatile"
13#check llvm {
14define #...@test.entry(ptr #...%0) #...{
15#...store volatile i16 123, ptr %0#...
16#...store volatile i16 321, ptr %0#...
17}
18
19#}
20
21#write test.zig {
22export fn entry(ptr: *volatile i16) void {
23 entry2(ptr[0..1]);
24}
25fn entry2(slice: []volatile i16) void {
26 @setRuntimeSafety(false);
27 slice[0] = 123;
28 slice[0] = 321;
29}
30#}
31#update "volatile slice"
32#check llvm {
33define #...@test.entry(#...) #...{
34#...
35}
36
37#...
38define #...@test.entry2(#...) #...{
39#...store volatile i16 123, ptr %#...
40#...store volatile i16 321, ptr %#...
41}
42
43#}
test/llvm-ir/load_store_bool created+28
......@@ -0,0 +1,28 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn foo(a: *bool, b: *align(2) bool) void {
8 const tmp = a.*;
9 a.* = b.*;
10 b.* = tmp;
11}
12#}
13#update
14#check llvm {
15define #...void @test.foo(ptr #...%0, ptr #...%1) #...{
16#...
17 %5 = load i8, ptr %0, align 1#...
18 %6 = trunc nuw i8 %5 to i1#...
19 %8 = load i8, ptr %1, align 2#...
20 %9 = trunc nuw i8 %8 to i1#...
21 %10 = zext i1 %9 to i8#...
22 store i8 %10, ptr %0, align 1#...
23 %11 = zext i1 %6 to i8#...
24 store i8 %11, ptr %1, align 2#...
25 ret void#...
26}
27
28#}
test/llvm-ir/matrix.zon created+9
......@@ -0,0 +1,9 @@
1.{
2 .{
3 .target = .{},
4 .cache_mode = .whole,
5 .backend = .llvmir,
6 .linker = .old,
7 .pic = .pic,
8 },
9}
test/llvm-ir/nonnull created+30
......@@ -0,0 +1,30 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn entry(ptr: *i16) i16 {
8 return ptr.*;
9}
10#}
11#update "store"
12#check llvm {
13define #...@test.entry(ptr #...nonnull #...%0) #...{
14#...load i16, ptr %0#...
15}
16
17#}
18
19#write test.zig {
20export fn entry(ptr: *i16) void {
21 ptr.* = 42;
22}
23#}
24#update "load"
25#check llvm {
26define #...@test.entry(ptr #...nonnull #...%0) #...{
27#...store i16 42, ptr %0#...
28}
29
30#}
test/llvm-ir/unused_load created+79
......@@ -0,0 +1,79 @@
1#obj {
2--name test
3-Mroot=test.zig
4#}
5
6#write test.zig {
7export fn entry(ptr: *i16) void {
8 _ = @atomicLoad(i16, ptr, .acquire);
9}
10#}
11#update "atomic acquire"
12#check llvm {
13define #...@test.entry(ptr #...%0) #...{
14#...load atomic i16, ptr %0 acquire#...
15}
16
17#}
18
19#write test.zig {
20export fn entry(ptr: *volatile i16) void {
21 _ = @atomicLoad(i16, ptr, .unordered);
22}
23#}
24#update "atomic volatile unordered"
25#check llvm {
26define #...@test.entry(ptr #...%0) #...{
27#...load atomic volatile i16, ptr %0 unordered#...
28}
29
30#}
31
32#write test.zig {
33export fn entry(ptr: *volatile i16) void {
34 _ = ptr.*;
35}
36#}
37#update "volatile"
38#check llvm {
39define #...@test.entry(ptr #...%0) #...{
40#...load volatile i16, ptr %0#...
41}
42
43#}
44
45#write test.zig {
46export fn entry(ptr: *volatile i16) void {
47 entry2(ptr[0..1]);
48}
49fn entry2(slice: []volatile i16) void {
50 @setRuntimeSafety(false);
51 _ = slice[0];
52}
53#}
54#update "volatile slice"
55#check llvm {
56define #...@test.entry(#...) #...{
57#...
58}
59
60#...
61define #...@test.entry2(#...) #...{
62#...load volatile i16, ptr %#...
63}
64
65#}
66
67#write test.zig {
68const S = packed struct(u16) { a: u2, b: u8, c: u6 };
69export fn entry(ptr: *volatile S) void {
70 _ = ptr.b;
71}
72#}
73#update "volatile packed"
74#check llvm {
75define #...@test.entry(ptr #...%0) #...{
76#...load volatile i16, ptr %#...
77}
78
79#}
test/llvm_ir.zig deleted-170
......@@ -1,170 +0,0 @@
1pub fn addCases(cases: *tests.LlvmIrContext) void {
2 cases.addMatches("nonnull ptr load",
3 \\export fn entry(ptr: *i16) i16 {
4 \\ return ptr.*;
5 \\}
6 , &.{
7 "ptr nonnull",
8 "load i16, ptr %0",
9 }, .{});
10
11 cases.addMatches("nonnull ptr store",
12 \\export fn entry(ptr: *i16) void {
13 \\ ptr.* = 42;
14 \\}
15 , &.{
16 "ptr nonnull",
17 "store i16 42, ptr %0",
18 }, .{});
19
20 cases.addMatches("unused acquire atomic ptr load",
21 \\export fn entry(ptr: *i16) void {
22 \\ _ = @atomicLoad(i16, ptr, .acquire);
23 \\}
24 , &.{
25 "load atomic i16, ptr %0 acquire",
26 }, .{});
27
28 cases.addMatches("unused unordered atomic volatile ptr load",
29 \\export fn entry(ptr: *volatile i16) void {
30 \\ _ = @atomicLoad(i16, ptr, .unordered);
31 \\}
32 , &.{
33 "load atomic volatile i16, ptr %0 unordered",
34 }, .{});
35
36 cases.addMatches("unused volatile ptr load",
37 \\export fn entry(ptr: *volatile i16) void {
38 \\ _ = ptr.*;
39 \\}
40 , &.{
41 "load volatile i16, ptr %0",
42 }, .{});
43
44 cases.addMatches("dead volatile ptr store",
45 \\export fn entry(ptr: *volatile i16) void {
46 \\ ptr.* = 123;
47 \\ ptr.* = 321;
48 \\}
49 , &.{
50 "store volatile i16 123, ptr %0",
51 "store volatile i16 321, ptr %0",
52 }, .{});
53
54 cases.addMatches("unused volatile slice load",
55 \\export fn entry(ptr: *volatile i16) void {
56 \\ entry2(ptr[0..1]);
57 \\}
58 \\fn entry2(ptr: []volatile i16) void {
59 \\ _ = ptr[0];
60 \\}
61 , &.{
62 "load volatile i16, ptr",
63 }, .{});
64
65 cases.addMatches("dead volatile slice store",
66 \\export fn entry(ptr: *volatile i16) void {
67 \\ entry2(ptr[0..1]);
68 \\}
69 \\fn entry2(ptr: []volatile i16) void {
70 \\ ptr[0] = 123;
71 \\ ptr[0] = 321;
72 \\}
73 , &.{
74 "store volatile i16 123, ptr",
75 "store volatile i16 321, ptr",
76 }, .{});
77
78 cases.addMatches("unused volatile packed pointer load",
79 \\const S = packed struct(u16) { a: u2, b: u8, c: u6 };
80 \\export fn entry(ptr: *volatile S) void {
81 \\ _ = ptr.b;
82 \\}
83 , &.{
84 "load volatile i16, ptr",
85 }, .{});
86
87 cases.addMatches("allowzero ptr load",
88 \\export fn entry(ptr: *allowzero i16) i16 {
89 \\ return ptr.*;
90 \\}
91 , &.{
92 "null_pointer_is_valid",
93 "load i16, ptr %0",
94 }, .{});
95
96 cases.addMatches("allowzero ptr store",
97 \\export fn entry(ptr: *allowzero i16) void {
98 \\ ptr.* = 42;
99 \\}
100 , &.{
101 "null_pointer_is_valid",
102 "store i16 42, ptr %0",
103 }, .{});
104
105 cases.addMatches("allowzero slice load",
106 \\export fn entry(ptr: *allowzero i16) i16 {
107 \\ return entry2(ptr[0..1]);
108 \\}
109 \\fn entry2(ptr: []allowzero i16) i16 {
110 \\ return ptr[0];
111 \\}
112 , &.{
113 "null_pointer_is_valid",
114 "load i16, ptr",
115 }, .{});
116
117 cases.addMatches("allowzero slice store",
118 \\export fn entry(ptr: *allowzero i16) void {
119 \\ entry2(ptr[0..1]);
120 \\}
121 \\fn entry2(ptr: []allowzero i16) void {
122 \\ ptr[0] = 42;
123 \\}
124 , &.{
125 "null_pointer_is_valid",
126 "store i16 42, ptr",
127 }, .{});
128
129 cases.addMatches("load and store bool",
130 \\export fn foo(a: *bool, b: *align(2) bool) void {
131 \\ const tmp = a.*;
132 \\ a.* = b.*;
133 \\ b.* = tmp;
134 \\}
135 , &.{
136 // TODO: this should all be one multiline string literal, but `-femit-llvm-ir` is currently
137 // emitting CRLF on Windows, which is a pain to handle here. In future that option will emit
138 // unoptimized LLVM IR emitted directly from Zig, so that bug will go away.
139 " %3 = load i8, ptr %0, align 1",
140 " %4 = trunc nuw i8 %3 to i1",
141 " %5 = load i8, ptr %1, align 2",
142 " %6 = trunc nuw i8 %5 to i1",
143 " %7 = zext i1 %6 to i8",
144 " store i8 %7, ptr %0, align 1",
145 " %8 = zext i1 %4 to i8",
146 " store i8 %8, ptr %1, align 2",
147 }, .{ .strip = true });
148
149 cases.addMatches("array to vector coercion is one vector load",
150 \\export fn entry(arr: *const [16]u8) @Vector(16, u8) {
151 \\ return arr.*;
152 \\}
153 , &.{
154 "load <16 x i8>, ptr",
155 }, .{});
156
157 cases.addMatches("array to vector coercion feeding overlapping shuffles",
158 \\export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void {
159 \\ const q: @Vector(16, u8) = src[0..16].*;
160 \\ a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 });
161 \\ b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 });
162 \\}
163 , &.{
164 "load <16 x i8>, ptr",
165 "shufflevector <16 x i8>",
166 }, .{});
167}
168
169const std = @import("std");
170const tests = @import("tests.zig");
test/src/LlvmIr.zig deleted-135
......@@ -1,135 +0,0 @@
1b: *std.Build,
2options: Options,
3root_step: *std.Build.Step,
4
5pub const Options = struct {
6 enable_llvm: bool,
7 test_filters: []const []const u8,
8 test_target_filters: []const []const u8,
9};
10
11const TestCase = struct {
12 name: []const u8,
13 source: []const u8,
14 check: union(enum) {
15 matches: []const []const u8,
16 exact: []const u8,
17 },
18 params: Params,
19
20 pub const Params = struct {
21 code_model: std.builtin.CodeModel = .default,
22 dll_export_fns: ?bool = null,
23 dwarf_format: ?std.dwarf.Format = null,
24 error_tracing: ?bool = null,
25 no_builtin: ?bool = null,
26 omit_frame_pointer: ?bool = null,
27 // For most cases, we want to test the LLVM IR that we output; we don't want to be in the
28 // business of testing LLVM's optimization passes. `Debug` gets us the closest to that as it
29 // disables the vast majority of passes in LLVM.
30 optimize: std.builtin.Optimize = .debug,
31 pic: ?bool = null,
32 pie: ?bool = null,
33 red_zone: ?bool = null,
34 sanitize_thread: ?bool = null,
35 single_threaded: ?bool = null,
36 stack_check: ?bool = null,
37 stack_protector: ?bool = null,
38 strip: ?bool = null,
39 target: std.Target.Query = .{},
40 unwind_tables: ?std.builtin.UnwindTables = null,
41 valgrind: ?bool = null,
42 };
43};
44
45pub fn addMatches(
46 self: *LlvmIr,
47 name: []const u8,
48 source: []const u8,
49 matches: []const []const u8,
50 params: TestCase.Params,
51) void {
52 self.addCase(.{
53 .name = name,
54 .source = source,
55 .check = .{ .matches = matches },
56 .params = params,
57 });
58}
59
60pub fn addExact(
61 self: *LlvmIr,
62 name: []const u8,
63 source: []const u8,
64 expected: []const []const u8,
65 params: TestCase.Params,
66) void {
67 self.addCase(.{
68 .name = name,
69 .source = source,
70 .check = .{ .exact = expected },
71 .params = params,
72 });
73}
74
75pub fn addCase(self: *LlvmIr, case: TestCase) void {
76 const target = self.b.resolveTargetQuery(case.params.target);
77 if (self.options.test_target_filters.len > 0) {
78 const triple_txt = target.query.zigTriple(self.b.allocator) catch @panic("OOM");
79 for (self.options.test_target_filters) |filter| {
80 if (std.mem.find(u8, triple_txt, filter) != null) break;
81 } else return;
82 }
83
84 const name = std.fmt.allocPrint(self.b.allocator, "check llvm-ir {s}", .{case.name}) catch @panic("OOM");
85 if (self.options.test_filters.len > 0) {
86 for (self.options.test_filters) |filter| {
87 if (std.mem.find(u8, name, filter) != null) break;
88 } else return;
89 }
90
91 const obj = self.b.addObject(.{
92 .name = "test",
93 .root_module = self.b.createModule(.{
94 .root_source_file = self.b.addWriteFiles().add("test.zig", case.source),
95
96 .code_model = case.params.code_model,
97 .error_tracing = case.params.error_tracing,
98 .omit_frame_pointer = case.params.omit_frame_pointer,
99 .optimize = case.params.optimize,
100 .pic = case.params.pic,
101 .sanitize_thread = case.params.sanitize_thread,
102 .single_threaded = case.params.single_threaded,
103 .strip = case.params.strip,
104 .target = target,
105 .unwind_tables = case.params.unwind_tables,
106 }),
107 .use_llvm = true,
108 });
109
110 obj.dll_export_fns = case.params.dll_export_fns;
111 obj.pie = case.params.pie;
112
113 obj.root_module.dwarf_format = case.params.dwarf_format;
114 obj.root_module.no_builtin = case.params.no_builtin;
115 obj.root_module.red_zone = case.params.red_zone;
116 obj.root_module.stack_check = case.params.stack_check;
117 obj.root_module.stack_protector = case.params.stack_protector;
118 obj.root_module.valgrind = case.params.valgrind;
119
120 // This is not very sophisticated at the moment. Eventually, we should move towards something
121 // like LLVM's `FileCheck` utility (https://llvm.org/docs/CommandGuide/FileCheck.html), though
122 // likely a more simplified version as we probably don't want a full-blown regex engine in the
123 // standard library...
124 const check = self.b.addCheckFile(obj.getEmittedLlvmIr(), switch (case.check) {
125 .matches => |m| .{ .expected_matches = m },
126 .exact => |e| .{ .expected_exact = e },
127 });
128 check.setName(name);
129 check.max_bytes = 64 * 1024 * 1024; // allow fairly big LLVM IR files
130
131 self.root_step.dependOn(&check.step);
132}
133
134const LlvmIr = @This();
135const std = @import("std");
test/tests.zig+1-22
......@@ -6,14 +6,12 @@ const OptimizeMode = std.builtin.Optimize;
66const Step = std.Build.Step;
77
88// Cases
9const llvm_ir = @import("llvm_ir.zig");
109const libc = @import("libc.zig");
1110const link = @import("link.zig");
1211
1312// Implementations
1413pub const ErrorTracesContext = @import("src/ErrorTrace.zig");
1514pub const StackTracesContext = @import("src/StackTrace.zig");
16pub const LlvmIrContext = @import("src/LlvmIr.zig");
1715pub const LibcContext = @import("src/Libc.zig");
1816pub const LinkContext = @import("src/Link.zig");
1917
......@@ -2196,7 +2194,7 @@ const link_targets = blk: {
21962194const RunnerTarget = struct {
21972195 target: std.Target.Query,
21982196 cache_mode: enum { whole, incremental },
2199 backend: enum { selfhosted, llvm, cbe },
2197 backend: enum { selfhosted, llvm, llvmir, cbe },
22002198 linker: enum { lld, old, new },
22012199 pic: enum { nopic, pic, pie },
22022200};
......@@ -3175,25 +3173,6 @@ fn isEditorFileName(name: []const u8) bool {
31753173 std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp");
31763174}
31773175
3178pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {
3179 const step = b.step("test-llvm-ir", "Run the LLVM IR tests");
3180
3181 if (!options.enable_llvm) {
3182 step.dependOn(&b.addFail("test-llvm-ir requires -Denable-llvm").step);
3183 return null;
3184 }
3185
3186 var context: LlvmIrContext = .{
3187 .b = b,
3188 .options = options,
3189 .root_step = step,
3190 };
3191
3192 llvm_ir.addCases(&context);
3193
3194 return step;
3195}
3196
31973176const libc_test_nsz_targets: []const std.Target.Query = &.{
31983177 .{
31993178 .cpu_arch = .arm,