authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-26 17:21:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-26 19:02:02-07:00
log87961237cf5ef8a2bdad39a8d30ec0fe0c998782
tree73621f71004a4ee2b50a5c6ad5bfeeaca158951a
parent00d6a4da4981a026222e387fe18915ab45e5c11d

add behavior test for tail calls

closes #9703

2 files changed, 60 insertions(+), 0 deletions(-)

test/behavior.zig+1
...@@ -149,6 +149,7 @@ test {...@@ -149,6 +149,7 @@ test {
149 _ = @import("behavior/byval_arg_var.zig");149 _ = @import("behavior/byval_arg_var.zig");
150 _ = @import("behavior/c_char_signedness.zig");150 _ = @import("behavior/c_char_signedness.zig");
151 _ = @import("behavior/call.zig");151 _ = @import("behavior/call.zig");
152 _ = @import("behavior/call_tail.zig");
152 _ = @import("behavior/cast.zig");153 _ = @import("behavior/cast.zig");
153 _ = @import("behavior/cast_int.zig");154 _ = @import("behavior/cast_int.zig");
154 _ = @import("behavior/comptime_memory.zig");155 _ = @import("behavior/comptime_memory.zig");
test/behavior/call_tail.zig created+59
...@@ -0,0 +1,59 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5var base: usize = undefined;
6var result_off: [7]usize = undefined;
7var result_len: [7]usize = undefined;
8var result_index: usize = 0;
9
10noinline fn insertionSort(data: []u64) void {
11 result_off[result_index] = @intFromPtr(data.ptr) - base;
12 result_len[result_index] = data.len;
13 result_index += 1;
14 if (data.len > 1) {
15 var least_i: usize = 0;
16 var i: usize = 1;
17 while (i < data.len) : (i += 1) {
18 if (data[i] < data[least_i])
19 least_i = i;
20 }
21 std.mem.swap(u64, &data[0], &data[least_i]);
22
23 // there used to be a bug where
24 // `data[1..]` is created on the stack
25 // and pointed to by the first argument register
26 // then stack is invalidated by the tailcall and
27 // overwritten by callee
28 // https://github.com/ziglang/zig/issues/9703
29 return @call(.always_tail, insertionSort, .{data[1..]});
30 }
31}
32
33test "arguments pointed to on stack into tailcall" {
34 switch (builtin.cpu.arch) {
35 .wasm32, .mips, .mipsel, .powerpc, .powerpcle, .powerpc64le => return error.SkipZigTest,
36 else => {},
37 }
38 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
40
41 var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 };
42 base = @intFromPtr(&data);
43 insertionSort(data[0..]);
44 try expect(result_len[0] == 7);
45 try expect(result_len[1] == 6);
46 try expect(result_len[2] == 5);
47 try expect(result_len[3] == 4);
48 try expect(result_len[4] == 3);
49 try expect(result_len[5] == 2);
50 try expect(result_len[6] == 1);
51
52 try expect(result_off[0] == 0);
53 try expect(result_off[1] == 8);
54 try expect(result_off[2] == 16);
55 try expect(result_off[3] == 24);
56 try expect(result_off[4] == 32);
57 try expect(result_off[5] == 40);
58 try expect(result_off[6] == 48);
59}