authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-15 14:01:01-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-08-15 14:01:01-07:00
log8b97a1aee2b161b9604d3b0c88166d0f0aef7e64
tree7a8d65ad3ef59679cf4318a2fea88b6979207de4
parent729807203a4ef162f39656be062dd11a428af8e3
parentd3672493cc6ad5085f202df1859b13b4ae4dec96
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3033 from ziglang/rewrite-coroutines

rework async function semantics

54 files changed, 5742 insertions(+), 5189 deletions(-)

CMakeLists.txt+1-1
......@@ -426,7 +426,6 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
426426set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")
427427
428428set(ZIG_SOURCES
429 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
430429 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
431430 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
432431 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
......@@ -438,6 +437,7 @@ set(ZIG_SOURCES
438437 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"
439438 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
440439 "${CMAKE_SOURCE_DIR}/src/error.cpp"
440 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
441441 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
442442 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
443443 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
build.zig+3-1
......@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {
375375 artifact.bundle_compiler_rt = true;
376376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
377377 artifact.linkSystemLibrary("c");
378 artifact.linkSystemLibrary("ntdll");
378 if (builtin.os == .windows) {
379 artifact.linkSystemLibrary("ntdll");
380 }
379381 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
380382 libuserland_step.dependOn(&artifact.step);
381383
doc/docgen.zig+1-2
......@@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
750750 .Keyword_async,
751751 .Keyword_await,
752752 .Keyword_break,
753 .Keyword_cancel,
754753 .Keyword_catch,
755754 .Keyword_comptime,
756755 .Keyword_const,
......@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
770769 .Keyword_or,
771770 .Keyword_orelse,
772771 .Keyword_packed,
773 .Keyword_promise,
772 .Keyword_anyframe,
774773 .Keyword_pub,
775774 .Keyword_resume,
776775 .Keyword_return,
doc/langref.html.in+332-170
......@@ -5968,55 +5968,27 @@ test "global assembly" {
59685968 <p>TODO: @atomic rmw</p>
59695969 <p>TODO: builtin atomic memory ordering enum</p>
59705970 {#header_close#}
5971 {#header_open|Coroutines#}
5971 {#header_open|Async Functions#}
59725972 <p>
5973 A coroutine is a generalization of a function.
5973 When a function is called, a frame is pushed to the stack,
5974 the function runs until it reaches a return statement, and then the frame is popped from the stack.
5975 At the callsite, the following code does not run until the function returns.
59745976 </p>
59755977 <p>
5976 When you call a function, it creates a stack frame,
5977 and then the function runs until it reaches a return
5978 statement, and then the stack frame is destroyed.
5979 At the callsite, the next line of code does not run
5980 until the function returns.
5978 An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
5979 followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
5980 provided explicitly by the caller, and it can be suspended and resumed any number of times.
59815981 </p>
59825982 <p>
5983 A coroutine is like a function, but it can be suspended
5984 and resumed any number of times, and then it must be
5985 explicitly destroyed. When a coroutine suspends, it
5986 returns to the resumer.
5987 </p>
5988 {#header_open|Minimal Coroutine Example#}
5989 <p>
5990 Declare a coroutine with the {#syntax#}async{#endsyntax#} keyword.
5991 The expression in angle brackets must evaluate to a struct
5992 which has these fields:
5993 </p>
5994 <ul>
5995 <li>{#syntax#}allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8{#endsyntax#} - where {#syntax#}Error{#endsyntax#} can be any error set.</li>
5996 <li>{#syntax#}freeFn: fn (self: *Allocator, old_mem: []u8) void{#endsyntax#}</li>
5997 </ul>
5998 <p>
5999 You may notice that this corresponds to the {#syntax#}std.mem.Allocator{#endsyntax#} interface.
6000 This makes it convenient to integrate with existing allocators. Note, however,
6001 that the language feature does not depend on the standard library, and any struct which
6002 has these fields is allowed.
6003 </p>
6004 <p>
6005 Omitting the angle bracket expression when defining an async function makes
6006 the function generic. Zig will infer the allocator type when the async function is called.
6007 </p>
6008 <p>
6009 Call a coroutine with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
6010 is a pointer to the allocator struct that the coroutine expects.
6011 </p>
6012 <p>
6013 The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
6014 is the return type of the async function. Once a promise has been created, it must be
6015 consumed, either with {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}:
5983 Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
5984 a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
5985 function call of an async function is a suspend point.
60165986 </p>
5987 {#header_open|Suspend and Resume#}
60175988 <p>
6018 Async functions start executing when created, so in the following example, the entire
6019 async function completes before it is canceled:
5989 At any point, a function may suspend itself. This causes control flow to
5990 return to the callsite (in the case of the first suspension),
5991 or resumer (in the case of subsequent suspensions).
60205992 </p>
60215993 {#code_begin|test#}
60225994const std = @import("std");
......@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;
60245996
60255997var x: i32 = 1;
60265998
6027test "create a coroutine and cancel it" {
6028 const p = try async<std.debug.global_allocator> simpleAsyncFn();
6029 comptime assert(@typeOf(p) == promise->void);
6030 cancel p;
5999test "suspend with no resume" {
6000 var frame = async func();
60316001 assert(x == 2);
60326002}
6033async<*std.mem.Allocator> fn simpleAsyncFn() void {
6034 x += 1;
6035}
6036 {#code_end#}
6037 {#header_close#}
6038 {#header_open|Suspend and Resume#}
6039 <p>
6040 At any point, an async function may suspend itself. This causes control flow to
6041 return to the caller or resumer. The following code demonstrates where control flow
6042 goes:
6043 </p>
6044 {#code_begin|test#}
6045const std = @import("std");
6046const assert = std.debug.assert;
6047
6048test "coroutine suspend, resume, cancel" {
6049 seq('a');
6050 const p = try async<std.debug.global_allocator> testAsyncSeq();
6051 seq('c');
6052 resume p;
6053 seq('f');
6054 cancel p;
6055 seq('g');
60566003
6057 assert(std.mem.eql(u8, points, "abcdefg"));
6058}
6059async fn testAsyncSeq() void {
6060 defer seq('e');
6061
6062 seq('b');
6004fn func() void {
6005 x += 1;
60636006 suspend;
6064 seq('d');
6065}
6066var points = [_]u8{0} ** "abcdefg".len;
6067var index: usize = 0;
6068
6069fn seq(c: u8) void {
6070 points[index] = c;
6071 index += 1;
6007 // This line is never reached because the suspend has no matching resume.
6008 x += 1;
60726009}
60736010 {#code_end#}
60746011 <p>
6075 When an async function suspends itself, it must be sure that it will be
6076 resumed or canceled somehow, for example by registering its promise handle
6077 in an event loop. Use a suspend capture block to gain access to the
6078 promise:
6012 In the same way that each allocation should have a corresponding free,
6013 Each {#syntax#}suspend{#endsyntax#} should have a corresponding {#syntax#}resume{#endsyntax#}.
6014 A <strong>suspend block</strong> allows a function to put a pointer to its own
6015 frame somewhere, for example into an event loop, even if that action will perform a
6016 {#syntax#}resume{#endsyntax#} operation on a different thread.
6017 {#link|@frame#} provides access to the async function frame pointer.
60796018 </p>
60806019 {#code_begin|test#}
60816020const std = @import("std");
60826021const assert = std.debug.assert;
60836022
6084test "coroutine suspend with block" {
6085 const p = try async<std.debug.global_allocator> testSuspendBlock();
6086 std.debug.assert(!result);
6087 resume a_promise;
6088 std.debug.assert(result);
6089 cancel p;
6023var the_frame: anyframe = undefined;
6024var result = false;
6025
6026test "async function suspend with block" {
6027 _ = async testSuspendBlock();
6028 assert(!result);
6029 resume the_frame;
6030 assert(result);
60906031}
60916032
6092var a_promise: promise = undefined;
6093var result = false;
6094async fn testSuspendBlock() void {
6033fn testSuspendBlock() void {
60956034 suspend {
6096 comptime assert(@typeOf(@handle()) == promise->void);
6097 a_promise = @handle();
6035 comptime assert(@typeOf(@frame()) == *@Frame(testSuspendBlock));
6036 the_frame = @frame();
60986037 }
60996038 result = true;
61006039}
61016040 {#code_end#}
61026041 <p>
6103 Every suspend point in an async function represents a point at which the coroutine
6104 could be destroyed. If that happens, {#syntax#}defer{#endsyntax#} expressions that are in
6105 scope are run, as well as {#syntax#}errdefer{#endsyntax#} expressions.
6106 </p>
6107 <p>
6108 {#link|Await#} counts as a suspend point.
6042 {#syntax#}suspend{#endsyntax#} causes a function to be {#syntax#}async{#endsyntax#}.
61096043 </p>
6044
61106045 {#header_open|Resuming from Suspend Blocks#}
61116046 <p>
6112 Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered
6047 Upon entering a {#syntax#}suspend{#endsyntax#} block, the async function is already considered
61136048 suspended, and can be resumed. For example, if you started another kernel thread,
6114 and had that thread call {#syntax#}resume{#endsyntax#} on the promise handle provided by the
6115 {#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend
6049 and had that thread call {#syntax#}resume{#endsyntax#} on the frame pointer provided by the
6050 {#link|@frame#}, the new thread would begin executing after the suspend
61166051 block, while the old thread continued executing the suspend block.
61176052 </p>
61186053 <p>
6119 However, the coroutine can be directly resumed from the suspend block, in which case it
6054 However, the async function can be directly resumed from the suspend block, in which case it
61206055 never returns to its resumer and continues executing.
61216056 </p>
61226057 {#code_begin|test#}
......@@ -6124,16 +6059,13 @@ const std = @import("std");
61246059const assert = std.debug.assert;
61256060
61266061test "resume from suspend" {
6127 var buf: [500]u8 = undefined;
6128 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
61296062 var my_result: i32 = 1;
6130 const p = try async<a> testResumeFromSuspend(&my_result);
6131 cancel p;
6063 _ = async testResumeFromSuspend(&my_result);
61326064 std.debug.assert(my_result == 2);
61336065}
6134async fn testResumeFromSuspend(my_result: *i32) void {
6066fn testResumeFromSuspend(my_result: *i32) void {
61356067 suspend {
6136 resume @handle();
6068 resume @frame();
61376069 }
61386070 my_result.* += 1;
61396071 suspend;
......@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {
61416073}
61426074 {#code_end#}
61436075 <p>
6144 This is guaranteed to be a tail call, and therefore will not cause a new stack frame.
6076 This is guaranteed to tail call, and therefore will not cause a new stack frame.
61456077 </p>
61466078 {#header_close#}
61476079 {#header_close#}
6148 {#header_open|Await#}
6080
6081 {#header_open|Async and Await#}
61496082 <p>
6150 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6151 {#syntax#}return{#endsyntax#} statement.
6083 In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
6084 {#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}.
61526085 </p>
6086 {#code_begin|test#}
6087const std = @import("std");
6088const assert = std.debug.assert;
6089
6090test "async and await" {
6091 // Here we have an exception where we do not match an async
6092 // with an await. The test block is not async and so cannot
6093 // have a suspend point in it.
6094 // This is well-defined behavior, and everything is OK here.
6095 // Note however that there would be no way to collect the
6096 // return value of amain, if it were something other than void.
6097 _ = async amain();
6098}
6099
6100fn amain() void {
6101 var frame = async func();
6102 comptime assert(@typeOf(frame) == @Frame(func));
6103
6104 const ptr: anyframe->void = &frame;
6105 const any_ptr: anyframe = ptr;
6106
6107 resume any_ptr;
6108 await ptr;
6109}
6110
6111fn func() void {
6112 suspend;
6113}
6114 {#code_end#}
61536115 <p>
6154 {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes
6155 as an operand a promise handle.
6156 If the async function associated with the promise handle has already returned,
6157 then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
6158 Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
6159 promise handle with the target coroutine. It becomes the target coroutine's responsibility
6160 to have ensured that it will be resumed or destroyed. When the target coroutine reaches
6161 its return statement, it gives the return value to the awaiter, destroys itself, and then
6162 resumes the awaiter.
6116 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6117 {#syntax#}return{#endsyntax#} statement.
61636118 </p>
61646119 <p>
6165 A promise handle must be consumed exactly once after it is created, either by {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}.
6120 {#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that
6121 implicitly casts to {#syntax#}anyframe->T{#endsyntax#}.
61666122 </p>
61676123 <p>
6168 {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},
6169 a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.
6124 There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
6125 It is the other way around: it suspends until the target function completes.
6126 In the event that the target function has already completed, {#syntax#}await{#endsyntax#}
6127 does not suspend; instead it copies the
6128 return value directly from the target function's frame.
61706129 </p>
61716130 {#code_begin|test#}
61726131const std = @import("std");
61736132const assert = std.debug.assert;
61746133
6175var a_promise: promise = undefined;
6134var the_frame: anyframe = undefined;
61766135var final_result: i32 = 0;
61776136
6178test "coroutine await" {
6137test "async function await" {
61796138 seq('a');
6180 const p = async<std.debug.global_allocator> amain() catch unreachable;
6139 _ = async amain();
61816140 seq('f');
6182 resume a_promise;
6141 resume the_frame;
61836142 seq('i');
61846143 assert(final_result == 1234);
61856144 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
61866145}
6187async fn amain() void {
6146fn amain() void {
61886147 seq('b');
6189 const p = async another() catch unreachable;
6148 var f = async another();
61906149 seq('e');
6191 final_result = await p;
6150 final_result = await f;
61926151 seq('h');
61936152}
6194async fn another() i32 {
6153fn another() i32 {
61956154 seq('c');
61966155 suspend {
61976156 seq('d');
6198 a_promise = @handle();
6157 the_frame = @frame();
61996158 }
62006159 seq('g');
62016160 return 1234;
......@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {
62116170 {#code_end#}
62126171 <p>
62136172 In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application
6214 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6215 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
6173 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6174 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
62166175 </p>
62176176 {#header_close#}
6218 {#header_open|Open Issues#}
6177
6178 {#header_open|Async Function Example#}
62196179 <p>
6220 There are a few issues with coroutines that are considered unresolved. Best be aware of them,
6221 as the situation is likely to change before 1.0.0:
6180 Putting all of this together, here is an example of typical
6181 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
6182 </p>
6183 {#code_begin|exe|async#}
6184const std = @import("std");
6185const Allocator = std.mem.Allocator;
6186
6187pub fn main() void {
6188 _ = async amainWrap();
6189
6190 // Typically we would use an event loop to manage resuming async functions,
6191 // but in this example we hard code what the event loop would do,
6192 // to make things deterministic.
6193 resume global_file_frame;
6194 resume global_download_frame;
6195}
6196
6197fn amainWrap() void {
6198 amain() catch |e| {
6199 std.debug.warn("{}\n", e);
6200 if (@errorReturnTrace()) |trace| {
6201 std.debug.dumpStackTrace(trace.*);
6202 }
6203 std.process.exit(1);
6204 };
6205}
6206
6207fn amain() !void {
6208 const allocator = std.heap.direct_allocator;
6209 var download_frame = async fetchUrl(allocator, "https://example.com/");
6210 var awaited_download_frame = false;
6211 errdefer if (!awaited_download_frame) {
6212 if (await download_frame) |r| allocator.free(r) else |_| {}
6213 };
6214
6215 var file_frame = async readFile(allocator, "something.txt");
6216 var awaited_file_frame = false;
6217 errdefer if (!awaited_file_frame) {
6218 if (await file_frame) |r| allocator.free(r) else |_| {}
6219 };
6220
6221 awaited_file_frame = true;
6222 const file_text = try await file_frame;
6223 defer allocator.free(file_text);
6224
6225 awaited_download_frame = true;
6226 const download_text = try await download_frame;
6227 defer allocator.free(download_text);
6228
6229 std.debug.warn("download_text: {}\n", download_text);
6230 std.debug.warn("file_text: {}\n", file_text);
6231}
6232
6233var global_download_frame: anyframe = undefined;
6234fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6235 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6236 errdefer allocator.free(result);
6237 suspend {
6238 global_download_frame = @frame();
6239 }
6240 std.debug.warn("fetchUrl returning\n");
6241 return result;
6242}
6243
6244var global_file_frame: anyframe = undefined;
6245fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6246 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6247 errdefer allocator.free(result);
6248 suspend {
6249 global_file_frame = @frame();
6250 }
6251 std.debug.warn("readFile returning\n");
6252 return result;
6253}
6254 {#code_end#}
6255 <p>
6256 Now we remove the {#syntax#}suspend{#endsyntax#} and {#syntax#}resume{#endsyntax#} code, and
6257 observe the same behavior, with one tiny difference:
6258 </p>
6259 {#code_begin|exe|blocking#}
6260const std = @import("std");
6261const Allocator = std.mem.Allocator;
6262
6263pub fn main() void {
6264 _ = async amainWrap();
6265}
6266
6267fn amainWrap() void {
6268 amain() catch |e| {
6269 std.debug.warn("{}\n", e);
6270 if (@errorReturnTrace()) |trace| {
6271 std.debug.dumpStackTrace(trace.*);
6272 }
6273 std.process.exit(1);
6274 };
6275}
6276
6277fn amain() !void {
6278 const allocator = std.heap.direct_allocator;
6279 var download_frame = async fetchUrl(allocator, "https://example.com/");
6280 var awaited_download_frame = false;
6281 errdefer if (!awaited_download_frame) {
6282 if (await download_frame) |r| allocator.free(r) else |_| {}
6283 };
6284
6285 var file_frame = async readFile(allocator, "something.txt");
6286 var awaited_file_frame = false;
6287 errdefer if (!awaited_file_frame) {
6288 if (await file_frame) |r| allocator.free(r) else |_| {}
6289 };
6290
6291 awaited_file_frame = true;
6292 const file_text = try await file_frame;
6293 defer allocator.free(file_text);
6294
6295 awaited_download_frame = true;
6296 const download_text = try await download_frame;
6297 defer allocator.free(download_text);
6298
6299 std.debug.warn("download_text: {}\n", download_text);
6300 std.debug.warn("file_text: {}\n", file_text);
6301}
6302
6303fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6304 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6305 errdefer allocator.free(result);
6306 std.debug.warn("fetchUrl returning\n");
6307 return result;
6308}
6309
6310fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6311 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6312 errdefer allocator.free(result);
6313 std.debug.warn("readFile returning\n");
6314 return result;
6315}
6316 {#code_end#}
6317 <p>
6318 Previously, the {#syntax#}fetchUrl{#endsyntax#} and {#syntax#}readFile{#endsyntax#} functions suspended,
6319 and were resumed in an order determined by the {#syntax#}main{#endsyntax#} function. Now,
6320 since there are no suspend points, the order of the printed "... returning" messages
6321 is determined by the order of {#syntax#}async{#endsyntax#} callsites.
62226322 </p>
6223 <ul>
6224 <li>Async functions have optimizations disabled - even in release modes - due to an
6225 <a href="https://github.com/ziglang/zig/issues/802">LLVM bug</a>.
6226 </li>
6227 <li>
6228 There are some situations where we can know statically that there will not be
6229 memory allocation failure, but Zig still forces us to handle it.
6230 TODO file an issue for this and link it here.
6231 </li>
6232 <li>
6233 Zig does not take advantage of LLVM's allocation elision optimization for
6234 coroutines. It crashed LLVM when I tried to do it the first time. This is
6235 related to the other 2 bullet points here. See
6236 <a href="https://github.com/ziglang/zig/issues/802">#802</a>.
6237 </li>
6238 </ul>
62396323 {#header_close#}
62406324
62416325 {#header_close#}
......@@ -6293,6 +6377,49 @@ comptime {
62936377 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
62946378 </p>
62956379 {#header_close#}
6380
6381 {#header_open|@asyncCall#}
6382 <pre>{#syntax#}@asyncCall(frame_buffer: []u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre>
6383 <p>
6384 {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer,
6385 which may or may not be an {#link|async function|Async Functions#}.
6386 </p>
6387 <p>
6388 The provided {#syntax#}frame_buffer{#endsyntax#} must be large enough to fit the entire function frame.
6389 This size can be determined with {#link|@frameSize#}. To provide a too-small buffer
6390 invokes safety-checked {#link|Undefined Behavior#}.
6391 </p>
6392 <p>
6393 {#syntax#}result_ptr{#endsyntax#} is optional ({#link|null#} may be provided). If provided,
6394 the function call will write its result directly to the result pointer, which will be available to
6395 read after {#link|await|Async and Await#} completes. Any result location provided to
6396 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
6397 </p>
6398 {#code_begin|test#}
6399const std = @import("std");
6400const assert = std.debug.assert;
6401
6402test "async fn pointer in a struct field" {
6403 var data: i32 = 1;
6404 const Foo = struct {
6405 bar: async fn (*i32) void,
6406 };
6407 var foo = Foo{ .bar = func };
6408 var bytes: [64]u8 = undefined;
6409 const f = @asyncCall(&bytes, {}, foo.bar, &data);
6410 assert(data == 2);
6411 resume f;
6412 assert(data == 4);
6413}
6414
6415async fn func(y: *i32) void {
6416 defer y.* += 2;
6417 y.* += 1;
6418 suspend;
6419}
6420 {#code_end#}
6421 {#header_close#}
6422
62966423 {#header_open|@atomicLoad#}
62976424 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
62986425 <p>
......@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}
68837010 {#see_also|@intToFloat#}
68847011 {#header_close#}
68857012
7013 {#header_open|@frame#}
7014 <pre>{#syntax#}@frame() *@Frame(func){#endsyntax#}</pre>
7015 <p>
7016 This function returns a pointer to the frame for a given function. This type
7017 can be {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyframe->T{#endsyntax#} and
7018 to {#syntax#}anyframe{#endsyntax#}, where {#syntax#}T{#endsyntax#} is the return type
7019 of the function in scope.
7020 </p>
7021 <p>
7022 This function does not mark a suspension point, but it does cause the function in scope
7023 to become an {#link|async function|Async Functions#}.
7024 </p>
7025 {#header_close#}
7026
7027 {#header_open|@Frame#}
7028 <pre>{#syntax#}@Frame(func: var) type{#endsyntax#}</pre>
7029 <p>
7030 This function returns the frame type of a function. This works for {#link|Async Functions#}
7031 as well as any function without a specific calling convention.
7032 </p>
7033 <p>
7034 This type is suitable to be used as the return type of {#link|async|Async and Await#} which
7035 allows one to, for example, heap-allocate an async function frame:
7036 </p>
7037 {#code_begin|test#}
7038const std = @import("std");
7039
7040test "heap allocated frame" {
7041 const frame = try std.heap.direct_allocator.create(@Frame(func));
7042 frame.* = async func();
7043}
7044
7045fn func() void {
7046 suspend;
7047}
7048 {#code_end#}
7049 {#header_close#}
7050
68867051 {#header_open|@frameAddress#}
68877052 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
68887053 <p>
......@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}
68987063 </p>
68997064 {#header_close#}
69007065
6901 {#header_open|@handle#}
6902 <pre>{#syntax#}@handle(){#endsyntax#}</pre>
7066 {#header_open|@frameSize#}
7067 <pre>{#syntax#}@frameSize() usize{#endsyntax#}</pre>
69037068 <p>
6904 This function returns a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
6905 is the return type of the async function in scope.
7069 This is the same as {#syntax#}@sizeOf(@Frame(func)){#endsyntax#}, where {#syntax#}func{#endsyntax#}
7070 may be runtime-known.
69067071 </p>
69077072 <p>
6908 This function is only valid within an async function scope.
7073 This function is typically used in conjunction with {#link|@asyncCall#}.
69097074 </p>
69107075 {#header_close#}
69117076
......@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {
80458210 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
80468211 <ul>
80478212 <li>All {#link|Thread Local Variables#} are treated as {#link|Global Variables#}.</li>
8048 <li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.
8049 TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
8213 <li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
80508214 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
80518215 and therefore various userland APIs which read this variable become more efficient.
80528216 For example {#syntax#}std.Mutex{#endsyntax#} becomes
......@@ -9793,7 +9957,6 @@ PrimaryExpr
97939957 &lt;- AsmExpr
97949958 / IfExpr
97959959 / KEYWORD_break BreakLabel? Expr?
9796 / KEYWORD_cancel Expr
97979960 / KEYWORD_comptime Expr
97989961 / KEYWORD_continue BreakLabel?
97999962 / KEYWORD_resume Expr
......@@ -10149,7 +10312,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word
1014910312KEYWORD_async &lt;- 'async' end_of_word
1015010313KEYWORD_await &lt;- 'await' end_of_word
1015110314KEYWORD_break &lt;- 'break' end_of_word
10152KEYWORD_cancel &lt;- 'cancel' end_of_word
1015310315KEYWORD_catch &lt;- 'catch' end_of_word
1015410316KEYWORD_comptime &lt;- 'comptime' end_of_word
1015510317KEYWORD_const &lt;- 'const' end_of_word
......@@ -10194,7 +10356,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word
1019410356KEYWORD_while &lt;- 'while' end_of_word
1019510357
1019610358keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm
10197 / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel
10359 / KEYWORD_async / KEYWORD_await / KEYWORD_break
1019810360 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
1019910361 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
1020010362 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
src-self-hosted/ir.zig-14
......@@ -1904,20 +1904,6 @@ pub const Builder = struct {
19041904 }
19051905 return error.Unimplemented;
19061906
1907 //ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
1908 //IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
1909 // get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
1910 //// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
1911 //IrInstruction *replacement_value = irb->exec->coro_handle;
1912 //IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
1913 // promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
1914 // AtomicRmwOp_xchg, AtomicOrderSeqCst);
1915 //ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
1916 //IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
1917 //IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
1918 //return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
1919 // is_comptime);
1920 //// the above blocks are rendered by ir_gen after the rest of codegen
19211907 }
19221908
19231909 const Ident = union(enum) {
src-self-hosted/link.zig+1-1
......@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
627627
628628fn addFnObjects(ctx: *Context) !void {
629629 // at this point it's guaranteed nobody else has this lock, so we circumvent it
630 // and avoid having to be a coroutine
630 // and avoid having to be an async function
631631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
632632
633633 var it = fn_link_set.first;
src-self-hosted/main.zig+9-12
......@@ -52,7 +52,7 @@ const Command = struct {
5252
5353pub fn main() !void {
5454 // This allocator needs to be thread-safe because we use it for the event.Loop
55 // which multiplexes coroutines onto kernel threads.
55 // which multiplexes async functions onto kernel threads.
5656 // libc allocator is guaranteed to have this property.
5757 const allocator = std.heap.c_allocator;
5858
......@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
466466 comp.link_objects = link_objects;
467467
468468 comp.start();
469 const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
470 defer cancel process_build_events_handle;
469 // TODO const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
471470 loop.run();
472471}
473472
......@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
578577 var zig_compiler = try ZigCompiler.init(&loop);
579578 defer zig_compiler.deinit();
580579
581 const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
582 defer cancel handle;
580 // TODO const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
583581
584582 loop.run();
585583}
......@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
663661 defer loop.deinit();
664662
665663 var result: FmtError!void = undefined;
666 const main_handle = try async<allocator> asyncFmtMainChecked(
667 &result,
668 &loop,
669 &flags,
670 color,
671 );
672 defer cancel main_handle;
664 // TODO const main_handle = try async<allocator> asyncFmtMainChecked(
665 // TODO &result,
666 // TODO &loop,
667 // TODO &flags,
668 // TODO color,
669 // TODO );
673670 loop.run();
674671 return result;
675672}
src-self-hosted/stage1.zig+2-1
......@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
142142 return Error.None;
143143}
144144
145// TODO: just use the actual self-hosted zig fmt. Until the coroutine rewrite, we use a blocking implementation.
145// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
146// we use a blocking implementation.
146147export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
147148 if (std.debug.runtime_safety) {
148149 fmtMain(argc, argv) catch unreachable;
src/all_types.hpp+161-216
......@@ -35,6 +35,7 @@ struct ConstExprValue;
3535struct IrInstruction;
3636struct IrInstructionCast;
3737struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;
3839struct IrBasicBlock;
3940struct ScopeDecls;
4041struct ZigWindowsSDK;
......@@ -70,20 +71,10 @@ struct IrExecutable {
7071 Scope *begin_scope;
7172 ZigList<Tld *> tld_list;
7273
73 IrInstruction *coro_handle;
74 IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
75 IrInstruction *coro_result_ptr_field_ptr;
76 IrInstruction *coro_result_field_ptr;
77 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
78 IrBasicBlock *coro_early_final;
79 IrBasicBlock *coro_normal_final;
80 IrBasicBlock *coro_suspend_block;
81 IrBasicBlock *coro_final_cleanup_block;
82 ZigVar *coro_allocator_var;
83
8474 bool invalid;
8575 bool is_inline;
8676 bool is_generic_instantiation;
77 bool need_err_code_spill;
8778};
8879
8980enum OutType {
......@@ -485,11 +476,10 @@ enum NodeType {
485476 NodeTypeIfErrorExpr,
486477 NodeTypeIfOptional,
487478 NodeTypeErrorSetDecl,
488 NodeTypeCancel,
489479 NodeTypeResume,
490480 NodeTypeAwaitExpr,
491481 NodeTypeSuspend,
492 NodeTypePromiseType,
482 NodeTypeAnyFrameType,
493483 NodeTypeEnumLiteral,
494484};
495485
......@@ -522,7 +512,6 @@ struct AstNodeFnProto {
522512 AstNode *section_expr;
523513
524514 bool auto_err_set;
525 AstNode *async_allocator_type;
526515};
527516
528517struct AstNodeFnDef {
......@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {
657646 bool is_builtin;
658647 bool is_async;
659648 bool seen; // used by @compileLog
660 AstNode *async_allocator;
661649};
662650
663651struct AstNodeArrayAccessExpr {
......@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {
922910 AstNode *expr; // may be null
923911};
924912
925struct AstNodeCancelExpr {
926 AstNode *expr;
927};
928
929913struct AstNodeResumeExpr {
930914 AstNode *expr;
931915};
......@@ -949,7 +933,7 @@ struct AstNodeSuspend {
949933 AstNode *block;
950934};
951935
952struct AstNodePromiseType {
936struct AstNodeAnyFrameType {
953937 AstNode *payload_type; // can be NULL
954938};
955939
......@@ -1014,13 +998,16 @@ struct AstNode {
1014998 AstNodeInferredArrayType inferred_array_type;
1015999 AstNodeErrorType error_type;
10161000 AstNodeErrorSetDecl err_set_decl;
1017 AstNodeCancelExpr cancel_expr;
10181001 AstNodeResumeExpr resume_expr;
10191002 AstNodeAwaitExpr await_expr;
10201003 AstNodeSuspend suspend;
1021 AstNodePromiseType promise_type;
1004 AstNodeAnyFrameType anyframe_type;
10221005 AstNodeEnumLiteral enum_literal;
10231006 } data;
1007
1008 // This is a function for use in the debugger to print
1009 // the source location.
1010 void src();
10241011};
10251012
10261013// this struct is allocated with allocate_nonzero
......@@ -1047,7 +1034,6 @@ struct FnTypeId {
10471034 bool is_var_args;
10481035 CallingConvention cc;
10491036 uint32_t alignment;
1050 ZigType *async_allocator_type;
10511037};
10521038
10531039uint32_t fn_type_id_hash(FnTypeId*);
......@@ -1095,6 +1081,7 @@ struct TypeStructField {
10951081 ConstExprValue *init_val; // null and then memoized
10961082 uint32_t bit_offset_in_host; // offset from the memory at gen_index
10971083 uint32_t host_int_bytes; // size of host integer
1084 uint32_t align;
10981085};
10991086
11001087enum ResolveStatus {
......@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {
11561143struct ZigTypeErrorUnion {
11571144 ZigType *err_set_type;
11581145 ZigType *payload_type;
1146 size_t pad_bytes;
1147 LLVMTypeRef pad_llvm_type;
11591148};
11601149
11611150struct ZigTypeErrorSet {
......@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {
12411230 ZigType *fn_type;
12421231};
12431232
1244struct ZigTypePromise {
1245 // null if `promise` instead of `promise->T`
1246 ZigType *result_type;
1247};
1248
12491233struct ZigTypeVector {
12501234 // The type must be a pointer, integer, or float
12511235 ZigType *elem_type;
......@@ -1276,7 +1260,8 @@ enum ZigTypeId {
12761260 ZigTypeIdBoundFn,
12771261 ZigTypeIdArgTuple,
12781262 ZigTypeIdOpaque,
1279 ZigTypeIdPromise,
1263 ZigTypeIdFnFrame,
1264 ZigTypeIdAnyFrame,
12801265 ZigTypeIdVector,
12811266 ZigTypeIdEnumLiteral,
12821267};
......@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {
12911276 Buf *bare_name;
12921277};
12931278
1279struct ZigTypeFnFrame {
1280 ZigFn *fn;
1281 ZigType *locals_struct;
1282};
1283
1284struct ZigTypeAnyFrame {
1285 ZigType *result_type; // null if `anyframe` instead of `anyframe->T`
1286};
1287
12941288struct ZigType {
12951289 ZigTypeId id;
12961290 Buf name;
......@@ -1314,16 +1308,16 @@ struct ZigType {
13141308 ZigTypeUnion unionation;
13151309 ZigTypeFn fn;
13161310 ZigTypeBoundFn bound_fn;
1317 ZigTypePromise promise;
13181311 ZigTypeVector vector;
13191312 ZigTypeOpaque opaque;
1313 ZigTypeFnFrame frame;
1314 ZigTypeAnyFrame any_frame;
13201315 } data;
13211316
13221317 // use these fields to make sure we don't duplicate type table entries for the same type
13231318 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]
13241319 ZigType *optional_parent;
1325 ZigType *promise_parent;
1326 ZigType *promise_frame_parent;
1320 ZigType *any_frame_parent;
13271321 // If we generate a constant name value for this type, we memoize it here.
13281322 // The type of this is array
13291323 ConstExprValue *cached_const_name_val;
......@@ -1359,7 +1353,6 @@ struct GlobalExport {
13591353};
13601354
13611355struct ZigFn {
1362 CodeGen *codegen;
13631356 LLVMValueRef llvm_value;
13641357 const char *llvm_name;
13651358 AstNode *proto_node;
......@@ -1368,7 +1361,17 @@ struct ZigFn {
13681361 Scope *child_scope; // parent is scope for last parameter
13691362 ScopeBlock *def_scope; // parent is child_scope
13701363 Buf symbol_name;
1371 ZigType *type_entry; // function type
1364 // This is the function type assuming the function does not suspend.
1365 // Note that for an async function, this can be shared with non-async functions. So the value here
1366 // should only be read for things in common between non-async and async function types.
1367 ZigType *type_entry;
1368 // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type.
1369 // However for functions that suspend, those values could possibly be their non-suspending equivalents.
1370 // So these values should be preferred.
1371 LLVMTypeRef raw_type_ref;
1372 ZigLLVMDIType *raw_di_type;
1373
1374 ZigType *frame_type;
13721375 // in the case of normal functions this is the implicit return type
13731376 // in the case of async functions this is the implicit return type according to the
13741377 // zig source code, not according to zig ir
......@@ -1379,6 +1382,7 @@ struct ZigFn {
13791382 size_t prealloc_backward_branch_quota;
13801383 AstNode **param_source_nodes;
13811384 Buf **param_names;
1385 IrInstruction *err_code_spill;
13821386
13831387 AstNode *fn_no_inline_set_node;
13841388 AstNode *fn_static_eval_set_node;
......@@ -1390,8 +1394,11 @@ struct ZigFn {
13901394 AstNode *set_alignstack_node;
13911395
13921396 AstNode *set_cold_node;
1397 const AstNode *inferred_async_node;
1398 ZigFn *inferred_async_fn;
13931399
13941400 ZigList<GlobalExport> export_list;
1401 ZigList<IrInstructionCallGen *> call_list;
13951402
13961403 LLVMValueRef valgrind_client_request_array;
13971404
......@@ -1442,8 +1449,6 @@ enum BuiltinFnId {
14421449 BuiltinFnIdErrName,
14431450 BuiltinFnIdBreakpoint,
14441451 BuiltinFnIdReturnAddress,
1445 BuiltinFnIdFrameAddress,
1446 BuiltinFnIdHandle,
14471452 BuiltinFnIdEmbedFile,
14481453 BuiltinFnIdCmpxchgWeak,
14491454 BuiltinFnIdCmpxchgStrong,
......@@ -1499,6 +1504,7 @@ enum BuiltinFnId {
14991504 BuiltinFnIdInlineCall,
15001505 BuiltinFnIdNoInlineCall,
15011506 BuiltinFnIdNewStackCall,
1507 BuiltinFnIdAsyncCall,
15021508 BuiltinFnIdTypeId,
15031509 BuiltinFnIdShlExact,
15041510 BuiltinFnIdShrExact,
......@@ -1514,6 +1520,10 @@ enum BuiltinFnId {
15141520 BuiltinFnIdAtomicLoad,
15151521 BuiltinFnIdHasDecl,
15161522 BuiltinFnIdUnionInit,
1523 BuiltinFnIdFrameAddress,
1524 BuiltinFnIdFrameType,
1525 BuiltinFnIdFrameHandle,
1526 BuiltinFnIdFrameSize,
15171527};
15181528
15191529struct BuiltinFnEntry {
......@@ -1541,6 +1551,12 @@ enum PanicMsgId {
15411551 PanicMsgIdBadEnumValue,
15421552 PanicMsgIdFloatToInt,
15431553 PanicMsgIdPtrCastNull,
1554 PanicMsgIdBadResume,
1555 PanicMsgIdBadAwait,
1556 PanicMsgIdBadReturn,
1557 PanicMsgIdResumedAnAwaitingFn,
1558 PanicMsgIdFrameTooSmall,
1559 PanicMsgIdResumedFnPendingAwait,
15441560
15451561 PanicMsgIdCount,
15461562};
......@@ -1701,7 +1717,13 @@ struct CodeGen {
17011717 LLVMTargetMachineRef target_machine;
17021718 ZigLLVMDIFile *dummy_di_file;
17031719 LLVMValueRef cur_ret_ptr;
1720 LLVMValueRef cur_frame_ptr;
17041721 LLVMValueRef cur_fn_val;
1722 LLVMValueRef cur_async_switch_instr;
1723 LLVMValueRef cur_async_resume_index_ptr;
1724 LLVMValueRef cur_async_awaiter_ptr;
1725 LLVMBasicBlockRef cur_preamble_llvm_block;
1726 size_t cur_resume_block_count;
17051727 LLVMValueRef cur_err_ret_trace_val_arg;
17061728 LLVMValueRef cur_err_ret_trace_val_stack;
17071729 LLVMValueRef memcpy_fn_val;
......@@ -1709,28 +1731,16 @@ struct CodeGen {
17091731 LLVMValueRef trap_fn_val;
17101732 LLVMValueRef return_address_fn_val;
17111733 LLVMValueRef frame_address_fn_val;
1712 LLVMValueRef coro_destroy_fn_val;
1713 LLVMValueRef coro_id_fn_val;
1714 LLVMValueRef coro_alloc_fn_val;
1715 LLVMValueRef coro_size_fn_val;
1716 LLVMValueRef coro_begin_fn_val;
1717 LLVMValueRef coro_suspend_fn_val;
1718 LLVMValueRef coro_end_fn_val;
1719 LLVMValueRef coro_free_fn_val;
1720 LLVMValueRef coro_resume_fn_val;
1721 LLVMValueRef coro_save_fn_val;
1722 LLVMValueRef coro_promise_fn_val;
1723 LLVMValueRef coro_alloc_helper_fn_val;
1724 LLVMValueRef coro_frame_fn_val;
1725 LLVMValueRef merge_err_ret_traces_fn_val;
17261734 LLVMValueRef add_error_return_trace_addr_fn_val;
17271735 LLVMValueRef stacksave_fn_val;
17281736 LLVMValueRef stackrestore_fn_val;
17291737 LLVMValueRef write_register_fn_val;
1738 LLVMValueRef merge_err_ret_traces_fn_val;
17301739 LLVMValueRef sp_md_node;
17311740 LLVMValueRef err_name_table;
17321741 LLVMValueRef safety_crash_err_fn;
17331742 LLVMValueRef return_err_fn;
1743 LLVMTypeRef anyframe_fn_type;
17341744
17351745 // reminder: hash tables must be initialized before use
17361746 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
......@@ -1797,12 +1807,12 @@ struct CodeGen {
17971807 ZigType *entry_var;
17981808 ZigType *entry_global_error_set;
17991809 ZigType *entry_arg_tuple;
1800 ZigType *entry_promise;
18011810 ZigType *entry_enum_literal;
1811 ZigType *entry_any_frame;
18021812 } builtin_types;
1813
18031814 ZigType *align_amt_type;
18041815 ZigType *stack_trace_type;
1805 ZigType *ptr_to_stack_trace_type;
18061816 ZigType *err_tag_type;
18071817 ZigType *test_fn_type;
18081818
......@@ -1938,6 +1948,7 @@ struct ZigVar {
19381948 ZigType *var_type;
19391949 LLVMValueRef value_ref;
19401950 IrInstruction *is_comptime;
1951 IrInstruction *ptr_instruction;
19411952 // which node is the declaration of the variable
19421953 AstNode *decl_node;
19431954 ZigLLVMDILocalVariable *di_loc_var;
......@@ -1985,7 +1996,6 @@ enum ScopeId {
19851996 ScopeIdSuspend,
19861997 ScopeIdFnDef,
19871998 ScopeIdCompTime,
1988 ScopeIdCoroPrelude,
19891999 ScopeIdRuntime,
19902000};
19912001
......@@ -2109,7 +2119,6 @@ struct ScopeRuntime {
21092119struct ScopeSuspend {
21102120 Scope base;
21112121
2112 IrBasicBlock *resume_block;
21132122 bool reported_err;
21142123};
21152124
......@@ -2128,12 +2137,6 @@ struct ScopeFnDef {
21282137 ZigFn *fn_entry;
21292138};
21302139
2131// This scope is created to indicate that the code in the scope
2132// is auto-generated coroutine prelude stuff.
2133struct ScopeCoroPrelude {
2134 Scope base;
2135};
2136
21372140// synchronized with code in define_builtin_compile_vars
21382141enum AtomicOrder {
21392142 AtomicOrderUnordered,
......@@ -2231,7 +2234,7 @@ enum IrInstructionId {
22312234 IrInstructionIdSetRuntimeSafety,
22322235 IrInstructionIdSetFloatMode,
22332236 IrInstructionIdArrayType,
2234 IrInstructionIdPromiseType,
2237 IrInstructionIdAnyFrameType,
22352238 IrInstructionIdSliceType,
22362239 IrInstructionIdGlobalAsm,
22372240 IrInstructionIdAsm,
......@@ -2278,7 +2281,10 @@ enum IrInstructionId {
22782281 IrInstructionIdBreakpoint,
22792282 IrInstructionIdReturnAddress,
22802283 IrInstructionIdFrameAddress,
2281 IrInstructionIdHandle,
2284 IrInstructionIdFrameHandle,
2285 IrInstructionIdFrameType,
2286 IrInstructionIdFrameSizeSrc,
2287 IrInstructionIdFrameSizeGen,
22822288 IrInstructionIdAlignOf,
22832289 IrInstructionIdOverflowOp,
22842290 IrInstructionIdTestErrSrc,
......@@ -2321,35 +2327,16 @@ enum IrInstructionId {
23212327 IrInstructionIdImplicitCast,
23222328 IrInstructionIdResolveResult,
23232329 IrInstructionIdResetResult,
2324 IrInstructionIdResultPtr,
23252330 IrInstructionIdOpaqueType,
23262331 IrInstructionIdSetAlignStack,
23272332 IrInstructionIdArgType,
23282333 IrInstructionIdExport,
23292334 IrInstructionIdErrorReturnTrace,
23302335 IrInstructionIdErrorUnion,
2331 IrInstructionIdCancel,
2332 IrInstructionIdGetImplicitAllocator,
2333 IrInstructionIdCoroId,
2334 IrInstructionIdCoroAlloc,
2335 IrInstructionIdCoroSize,
2336 IrInstructionIdCoroBegin,
2337 IrInstructionIdCoroAllocFail,
2338 IrInstructionIdCoroSuspend,
2339 IrInstructionIdCoroEnd,
2340 IrInstructionIdCoroFree,
2341 IrInstructionIdCoroResume,
2342 IrInstructionIdCoroSave,
2343 IrInstructionIdCoroPromise,
2344 IrInstructionIdCoroAllocHelper,
23452336 IrInstructionIdAtomicRmw,
23462337 IrInstructionIdAtomicLoad,
2347 IrInstructionIdPromiseResultType,
2348 IrInstructionIdAwaitBookkeeping,
23492338 IrInstructionIdSaveErrRetAddr,
23502339 IrInstructionIdAddImplicitReturnType,
2351 IrInstructionIdMergeErrRetTraces,
2352 IrInstructionIdMarkErrRetTracePtr,
23532340 IrInstructionIdErrSetCast,
23542341 IrInstructionIdToBytes,
23552342 IrInstructionIdFromBytes,
......@@ -2365,6 +2352,13 @@ enum IrInstructionId {
23652352 IrInstructionIdEndExpr,
23662353 IrInstructionIdPtrOfArrayToSlice,
23672354 IrInstructionIdUnionInitNamedField,
2355 IrInstructionIdSuspendBegin,
2356 IrInstructionIdSuspendFinish,
2357 IrInstructionIdAwaitSrc,
2358 IrInstructionIdAwaitGen,
2359 IrInstructionIdResume,
2360 IrInstructionIdSpillBegin,
2361 IrInstructionIdSpillEnd,
23682362};
23692363
23702364struct IrInstruction {
......@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {
26072601 IrInstruction **args;
26082602 ResultLoc *result_loc;
26092603
2610 IrInstruction *async_allocator;
26112604 IrInstruction *new_stack;
26122605 FnInline fn_inline;
26132606 bool is_async;
......@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {
26222615 size_t arg_count;
26232616 IrInstruction **args;
26242617 IrInstruction *result_loc;
2618 IrInstruction *frame_result_loc;
26252619
2626 IrInstruction *async_allocator;
26272620 IrInstruction *new_stack;
26282621 FnInline fn_inline;
26292622 bool is_async;
......@@ -2639,7 +2632,7 @@ struct IrInstructionConst {
26392632struct IrInstructionReturn {
26402633 IrInstruction base;
26412634
2642 IrInstruction *value;
2635 IrInstruction *operand;
26432636};
26442637
26452638enum CastOp {
......@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {
27442737 bool is_allow_zero;
27452738};
27462739
2747struct IrInstructionPromiseType {
2740struct IrInstructionAnyFrameType {
27482741 IrInstruction base;
27492742
27502743 IrInstruction *payload_type;
......@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {
30843077 IrInstruction base;
30853078};
30863079
3087struct IrInstructionHandle {
3080struct IrInstructionFrameHandle {
3081 IrInstruction base;
3082};
3083
3084struct IrInstructionFrameType {
3085 IrInstruction base;
3086
3087 IrInstruction *fn;
3088};
3089
3090struct IrInstructionFrameSizeSrc {
3091 IrInstruction base;
3092
3093 IrInstruction *fn;
3094};
3095
3096struct IrInstructionFrameSizeGen {
30883097 IrInstruction base;
3098
3099 IrInstruction *fn;
30893100};
30903101
30913102enum IrOverflowOp {
......@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {
31273138 IrInstruction base;
31283139
31293140 bool resolve_err_set;
3141 bool base_ptr_is_payload;
31303142 IrInstruction *base_ptr;
31313143};
31323144
......@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {
31793191 IrInstruction **param_types;
31803192 IrInstruction *align_value;
31813193 IrInstruction *return_type;
3182 IrInstruction *async_allocator_type_value;
31833194 bool is_var_args;
31843195};
31853196
......@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {
34093420 IrInstruction *payload;
34103421};
34113422
3412struct IrInstructionCancel {
3413 IrInstruction base;
3414
3415 IrInstruction *target;
3416};
3417
3418enum ImplicitAllocatorId {
3419 ImplicitAllocatorIdArg,
3420 ImplicitAllocatorIdLocalVar,
3421};
3422
3423struct IrInstructionGetImplicitAllocator {
3424 IrInstruction base;
3425
3426 ImplicitAllocatorId id;
3427};
3428
3429struct IrInstructionCoroId {
3430 IrInstruction base;
3431
3432 IrInstruction *promise_ptr;
3433};
3434
3435struct IrInstructionCoroAlloc {
3436 IrInstruction base;
3437
3438 IrInstruction *coro_id;
3439};
3440
3441struct IrInstructionCoroSize {
3442 IrInstruction base;
3443};
3444
3445struct IrInstructionCoroBegin {
3446 IrInstruction base;
3447
3448 IrInstruction *coro_id;
3449 IrInstruction *coro_mem_ptr;
3450};
3451
3452struct IrInstructionCoroAllocFail {
3453 IrInstruction base;
3454
3455 IrInstruction *err_val;
3456};
3457
3458struct IrInstructionCoroSuspend {
3459 IrInstruction base;
3460
3461 IrInstruction *save_point;
3462 IrInstruction *is_final;
3463};
3464
3465struct IrInstructionCoroEnd {
3466 IrInstruction base;
3467};
3468
3469struct IrInstructionCoroFree {
3470 IrInstruction base;
3471
3472 IrInstruction *coro_id;
3473 IrInstruction *coro_handle;
3474};
3475
3476struct IrInstructionCoroResume {
3477 IrInstruction base;
3478
3479 IrInstruction *awaiter_handle;
3480};
3481
3482struct IrInstructionCoroSave {
3483 IrInstruction base;
3484
3485 IrInstruction *coro_handle;
3486};
3487
3488struct IrInstructionCoroPromise {
3489 IrInstruction base;
3490
3491 IrInstruction *coro_handle;
3492};
3493
3494struct IrInstructionCoroAllocHelper {
3495 IrInstruction base;
3496
3497 IrInstruction *realloc_fn;
3498 IrInstruction *coro_size;
3499};
3500
35013423struct IrInstructionAtomicRmw {
35023424 IrInstruction base;
35033425
......@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {
35193441 AtomicOrder resolved_ordering;
35203442};
35213443
3522struct IrInstructionPromiseResultType {
3523 IrInstruction base;
3524
3525 IrInstruction *promise_type;
3526};
3527
3528struct IrInstructionAwaitBookkeeping {
3529 IrInstruction base;
3530
3531 IrInstruction *promise_result_type;
3532};
3533
35343444struct IrInstructionSaveErrRetAddr {
35353445 IrInstruction base;
35363446};
......@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {
35413451 IrInstruction *value;
35423452};
35433453
3544struct IrInstructionMergeErrRetTraces {
3545 IrInstruction base;
3546
3547 IrInstruction *coro_promise_ptr;
3548 IrInstruction *src_err_ret_trace_ptr;
3549 IrInstruction *dest_err_ret_trace_ptr;
3550};
3551
3552struct IrInstructionMarkErrRetTracePtr {
3553 IrInstruction base;
3554
3555 IrInstruction *err_ret_trace_ptr;
3556};
3557
35583454// For float ops which take a single argument
35593455struct IrInstructionFloatOp {
35603456 IrInstruction base;
......@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {
36453541
36463542 uint32_t align;
36473543 const char *name_hint;
3544 size_t field_index;
36483545};
36493546
36503547struct IrInstructionEndExpr {
......@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {
36923589 IrInstruction *result_loc;
36933590};
36943591
3592struct IrInstructionSuspendBegin {
3593 IrInstruction base;
3594
3595 LLVMBasicBlockRef resume_bb;
3596};
3597
3598struct IrInstructionSuspendFinish {
3599 IrInstruction base;
3600
3601 IrInstructionSuspendBegin *begin;
3602};
3603
3604struct IrInstructionAwaitSrc {
3605 IrInstruction base;
3606
3607 IrInstruction *frame;
3608 ResultLoc *result_loc;
3609};
3610
3611struct IrInstructionAwaitGen {
3612 IrInstruction base;
3613
3614 IrInstruction *frame;
3615 IrInstruction *result_loc;
3616};
3617
3618struct IrInstructionResume {
3619 IrInstruction base;
3620
3621 IrInstruction *frame;
3622};
3623
3624enum SpillId {
3625 SpillIdInvalid,
3626 SpillIdRetErrCode,
3627};
3628
3629struct IrInstructionSpillBegin {
3630 IrInstruction base;
3631
3632 SpillId spill_id;
3633 IrInstruction *operand;
3634};
3635
3636struct IrInstructionSpillEnd {
3637 IrInstruction base;
3638
3639 IrInstructionSpillBegin *begin;
3640};
3641
36953642enum ResultLocId {
36963643 ResultLocIdInvalid,
36973644 ResultLocIdNone,
......@@ -3775,20 +3722,16 @@ static const size_t maybe_null_index = 1;
37753722static const size_t err_union_payload_index = 0;
37763723static const size_t err_union_err_index = 1;
37773724
3778// TODO call graph analysis to find out what this number needs to be for every function
3779// MUST BE A POWER OF TWO.
3780static const size_t stack_trace_ptr_count = 32;
3781
3782// these belong to the async function
3783#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3784#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3785#define RESULT_FIELD_NAME "result"
3786#define ASYNC_REALLOC_FIELD_NAME "reallocFn"
3787#define ASYNC_SHRINK_FIELD_NAME "shrinkFn"
3788#define ATOMIC_STATE_FIELD_NAME "atomic_state"
3789// these point to data belonging to the awaiter
3790#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3791#define RESULT_PTR_FIELD_NAME "result_ptr"
3725// label (grep this): [fn_frame_struct_layout]
3726static const size_t frame_fn_ptr_index = 0;
3727static const size_t frame_resume_index = 1;
3728static const size_t frame_awaiter_index = 2;
3729static const size_t frame_ret_start = 3;
3730
3731// TODO https://github.com/ziglang/zig/issues/3056
3732// We require this to be a power of 2 so that we can use shifting rather than
3733// remainder division.
3734static const size_t stack_trace_ptr_count = 32; // Must be a power of 2.
37923735
37933736#define NAMESPACE_SEP_CHAR '.'
37943737#define NAMESPACE_SEP_STR "."
......@@ -3811,11 +3754,13 @@ enum FnWalkId {
38113754
38123755struct FnWalkAttrs {
38133756 ZigFn *fn;
3757 LLVMValueRef llvm_fn;
38143758 unsigned gen_i;
38153759};
38163760
38173761struct FnWalkCall {
38183762 ZigList<LLVMValueRef> *gen_param_values;
3763 ZigList<ZigType *> *gen_param_types;
38193764 IrInstructionCallGen *inst;
38203765 bool is_var_args;
38213766};
src/analyze.cpp+873-238
......@@ -7,6 +7,7 @@
77
88#include "analyze.hpp"
99#include "ast_render.hpp"
10#include "codegen.hpp"
1011#include "config.h"
1112#include "error.hpp"
1213#include "ir.hpp"
......@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
3132static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
3233static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
3334
35// nullptr means not analyzed yet; this one means currently being analyzed
36static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
37// this one means analyzed and it's not async
38static const AstNode *inferred_async_none = reinterpret_cast<AstNode *>(0x2);
39
3440static bool is_top_level_struct(ZigType *import) {
3541 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
3642}
......@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
5662 return err;
5763}
5864
59ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
65ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
6066 Token fake_token;
6167 fake_token.start_line = node->line;
6268 fake_token.start_column = node->column;
6369 return add_token_error(g, node->owner, &fake_token, msg);
6470}
6571
66ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
72ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) {
6773 Token fake_token;
6874 fake_token.start_line = node->line;
6975 fake_token.start_column = node->column;
......@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
188194 return &scope->base;
189195}
190196
191Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
192 ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1);
193 init_scope(g, &scope->base, ScopeIdCoroPrelude, node, parent);
194 return &scope->base;
195}
196
197197ZigType *get_scope_import(Scope *scope) {
198198 while (scope) {
199199 if (scope->id == ScopeIdDecls) {
......@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
234234 return type_entry->data.enumeration.decl_node;
235235 case ZigTypeIdUnion:
236236 return type_entry->data.unionation.decl_node;
237 case ZigTypeIdFnFrame:
238 return type_entry->data.frame.fn->proto_node;
237239 case ZigTypeIdOpaque:
238240 case ZigTypeIdMetaType:
239241 case ZigTypeIdVoid:
......@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
254256 case ZigTypeIdFn:
255257 case ZigTypeIdBoundFn:
256258 case ZigTypeIdArgTuple:
257 case ZigTypeIdPromise:
258259 case ZigTypeIdVector:
260 case ZigTypeIdAnyFrame:
259261 return nullptr;
260262 }
261263 zig_unreachable();
......@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
269271 return type_entry->data.structure.resolve_status >= status;
270272 case ZigTypeIdUnion:
271273 return type_entry->data.unionation.resolve_status >= status;
274 case ZigTypeIdFnFrame:
275 switch (status) {
276 case ResolveStatusInvalid:
277 zig_unreachable();
278 case ResolveStatusUnstarted:
279 case ResolveStatusZeroBitsKnown:
280 return true;
281 case ResolveStatusAlignmentKnown:
282 case ResolveStatusSizeKnown:
283 return type_entry->data.frame.locals_struct != nullptr;
284 case ResolveStatusLLVMFwdDecl:
285 case ResolveStatusLLVMFull:
286 return type_entry->llvm_type != nullptr;
287 }
272288 case ZigTypeIdEnum:
273289 switch (status) {
274290 case ResolveStatusUnstarted:
......@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
307323 case ZigTypeIdFn:
308324 case ZigTypeIdBoundFn:
309325 case ZigTypeIdArgTuple:
310 case ZigTypeIdPromise:
311326 case ZigTypeIdVector:
327 case ZigTypeIdAnyFrame:
312328 return true;
313329 }
314330 zig_unreachable();
......@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
341357 return get_int_type(g, false, bits_needed_for_unsigned(x));
342358}
343359
344ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
345 if (result_type != nullptr && result_type->promise_parent != nullptr) {
346 return result_type->promise_parent;
347 } else if (result_type == nullptr && g->builtin_types.entry_promise != nullptr) {
348 return g->builtin_types.entry_promise;
360ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) {
361 if (result_type != nullptr && result_type->any_frame_parent != nullptr) {
362 return result_type->any_frame_parent;
363 } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) {
364 return g->builtin_types.entry_any_frame;
349365 }
350366
351 ZigType *entry = new_type_table_entry(ZigTypeIdPromise);
367 ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame);
352368 entry->abi_size = g->builtin_types.entry_usize->abi_size;
353369 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
354370 entry->abi_align = g->builtin_types.entry_usize->abi_align;
355 entry->data.promise.result_type = result_type;
356 buf_init_from_str(&entry->name, "promise");
371 entry->data.any_frame.result_type = result_type;
372 buf_init_from_str(&entry->name, "anyframe");
357373 if (result_type != nullptr) {
358374 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
359375 }
360376
361377 if (result_type != nullptr) {
362 result_type->promise_parent = entry;
378 result_type->any_frame_parent = entry;
363379 } else if (result_type == nullptr) {
364 g->builtin_types.entry_promise = entry;
380 g->builtin_types.entry_any_frame = entry;
365381 }
366382 return entry;
367383}
......@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
378394 zig_unreachable();
379395}
380396
397ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
398 if (fn->frame_type != nullptr) {
399 return fn->frame_type;
400 }
401
402 ZigType *entry = new_type_table_entry(ZigTypeIdFnFrame);
403 buf_resize(&entry->name, 0);
404 buf_appendf(&entry->name, "@Frame(%s)", buf_ptr(&fn->symbol_name));
405
406 entry->data.frame.fn = fn;
407
408 // Async function frames are always non-zero bits because they always have a resume index.
409 entry->abi_size = SIZE_MAX;
410 entry->size_in_bits = SIZE_MAX;
411
412 fn->frame_type = entry;
413 return entry;
414}
415
381416ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
382417 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
383418 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
......@@ -490,42 +525,6 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
490525 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
491526}
492527
493ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
494 if (return_type->promise_frame_parent != nullptr) {
495 return return_type->promise_frame_parent;
496 }
497
498 ZigType *atomic_state_type = g->builtin_types.entry_usize;
499 ZigType *result_ptr_type = get_pointer_to_type(g, return_type, false);
500
501 ZigList<const char *> field_names = {};
502 field_names.append(ATOMIC_STATE_FIELD_NAME);
503 field_names.append(RESULT_FIELD_NAME);
504 field_names.append(RESULT_PTR_FIELD_NAME);
505 if (g->have_err_ret_tracing) {
506 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
507 field_names.append(ERR_RET_TRACE_FIELD_NAME);
508 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
509 }
510
511 ZigList<ZigType *> field_types = {};
512 field_types.append(atomic_state_type);
513 field_types.append(return_type);
514 field_types.append(result_ptr_type);
515 if (g->have_err_ret_tracing) {
516 field_types.append(get_ptr_to_stack_trace_type(g));
517 field_types.append(g->stack_trace_type);
518 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
519 }
520
521 assert(field_names.length == field_types.length);
522 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
523 ZigType *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
524
525 return_type->promise_frame_parent = entry;
526 return entry;
527}
528
529528ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
530529 if (child_type->optional_parent != nullptr) {
531530 return child_type->optional_parent;
......@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
631630 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);
632631 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);
633632 entry->size_in_bits = entry->abi_size * 8;
633 entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]);
634634 }
635635
636636 g->type_table.put(type_id, entry);
......@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
828828 zig_unreachable();
829829}
830830
831ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {
831ZigType *get_stack_trace_type(CodeGen *g) {
832832 if (g->stack_trace_type == nullptr) {
833833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
834834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);
835835
836836 g->stack_trace_type = stack_trace_type_val->data.x_type;
837837 assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));
838
839 g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false);
840838 }
841 return g->ptr_to_stack_trace_type;
839 return g->stack_trace_type;
842840}
843841
844842bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
......@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
879877
880878 // populate the name of the type
881879 buf_resize(&fn_type->name, 0);
882 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
883 assert(fn_type_id->async_allocator_type != nullptr);
884 buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name));
885 } else {
886 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
887 buf_appendf(&fn_type->name, "%s", cc_str);
888 }
880 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
881 buf_appendf(&fn_type->name, "%s", cc_str);
889882 buf_appendf(&fn_type->name, "fn(");
890883 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
891884 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
......@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
998991ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
999992 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);
1000993 buf_resize(&fn_type->name, 0);
1001 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
1002 const char *async_allocator_type_str = (fn_type->data.fn.fn_type_id.async_allocator_type == nullptr) ?
1003 "var" : buf_ptr(&fn_type_id->async_allocator_type->name);
1004 buf_appendf(&fn_type->name, "async(%s) ", async_allocator_type_str);
1005 } else {
1006 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1007 buf_appendf(&fn_type->name, "%s", cc_str);
1008 }
994 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
995 buf_appendf(&fn_type->name, "%s", cc_str);
1009996 buf_appendf(&fn_type->name, "fn(");
1010997 size_t i = 0;
1011998 for (; i < fn_type_id->next_param_index; i += 1) {
......@@ -1119,7 +1106,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
11191106 case ZigTypeIdBoundFn:
11201107 case ZigTypeIdArgTuple:
11211108 case ZigTypeIdOpaque:
1122 case ZigTypeIdPromise:
1109 case ZigTypeIdFnFrame:
1110 case ZigTypeIdAnyFrame:
11231111 add_node_error(g, source_node,
11241112 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
11251113 buf_ptr(&type_entry->name)));
......@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
12071195 case ZigTypeIdErrorSet:
12081196 case ZigTypeIdBoundFn:
12091197 case ZigTypeIdArgTuple:
1210 case ZigTypeIdPromise:
12111198 case ZigTypeIdVoid:
1199 case ZigTypeIdFnFrame:
1200 case ZigTypeIdAnyFrame:
12121201 return false;
12131202 case ZigTypeIdOpaque:
12141203 case ZigTypeIdUnreachable:
......@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
13781367 case ZigTypeIdEnum:
13791368 case ZigTypeIdUnion:
13801369 case ZigTypeIdFn:
1381 case ZigTypeIdPromise:
13821370 case ZigTypeIdVector:
1371 case ZigTypeIdFnFrame:
1372 case ZigTypeIdAnyFrame:
13831373 switch (type_requires_comptime(g, type_entry)) {
13841374 case ReqCompTimeNo:
13851375 break;
......@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
14741464 case ZigTypeIdEnum:
14751465 case ZigTypeIdUnion:
14761466 case ZigTypeIdFn:
1477 case ZigTypeIdPromise:
14781467 case ZigTypeIdVector:
1468 case ZigTypeIdFnFrame:
1469 case ZigTypeIdAnyFrame:
14791470 switch (type_requires_comptime(g, fn_type_id.return_type)) {
14801471 case ReqCompTimeInvalid:
14811472 return g->builtin_types.entry_invalid;
......@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
14871478 break;
14881479 }
14891480
1490 if (fn_type_id.cc == CallingConventionAsync) {
1491 if (fn_proto->async_allocator_type == nullptr) {
1492 return get_generic_fn_type(g, &fn_type_id);
1493 }
1494 fn_type_id.async_allocator_type = analyze_type_expr(g, child_scope, fn_proto->async_allocator_type);
1495 if (type_is_invalid(fn_type_id.async_allocator_type)) {
1496 return g->builtin_types.entry_invalid;
1497 }
1498 }
1499
15001481 return get_fn_type(g, &fn_type_id);
15011482}
15021483
......@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {
15161497 zig_unreachable();
15171498}
15181499
1500struct SrcField {
1501 const char *name;
1502 ZigType *ty;
1503 unsigned align;
1504};
15191505
1520ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
1521 ZigType *field_types[], size_t field_count)
1506static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count,
1507 unsigned min_abi_align)
15221508{
15231509 ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
15241510
......@@ -1530,22 +1516,20 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15301516 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
15311517 struct_type->data.structure.fields_by_name.init(field_count);
15321518
1533 size_t abi_align = 0;
1519 size_t abi_align = min_abi_align;
15341520 for (size_t i = 0; i < field_count; i += 1) {
15351521 TypeStructField *field = &struct_type->data.structure.fields[i];
1536 field->name = buf_create_from_str(field_names[i]);
1537 field->type_entry = field_types[i];
1522 field->name = buf_create_from_str(fields[i].name);
1523 field->type_entry = fields[i].ty;
15381524 field->src_index = i;
1525 field->align = fields[i].align;
15391526
15401527 if (type_has_bits(field->type_entry)) {
15411528 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));
1542 if (field->type_entry->abi_align > abi_align) {
1543 abi_align = field->type_entry->abi_align;
1529 unsigned field_abi_align = max(field->align, field->type_entry->abi_align);
1530 if (field_abi_align > abi_align) {
1531 abi_align = field_abi_align;
15441532 }
1545 field->gen_index = struct_type->data.structure.gen_field_count;
1546 struct_type->data.structure.gen_field_count += 1;
1547 } else {
1548 field->gen_index = SIZE_MAX;
15491533 }
15501534
15511535 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
......@@ -1555,17 +1539,24 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15551539 size_t next_offset = 0;
15561540 for (size_t i = 0; i < field_count; i += 1) {
15571541 TypeStructField *field = &struct_type->data.structure.fields[i];
1558 if (field->gen_index == SIZE_MAX)
1542 if (!type_has_bits(field->type_entry))
15591543 continue;
1544
15601545 field->offset = next_offset;
1546
1547 // find the next non-zero-byte field for offset calculations
15611548 size_t next_src_field_index = i + 1;
15621549 for (; next_src_field_index < field_count; next_src_field_index += 1) {
1563 if (struct_type->data.structure.fields[next_src_field_index].gen_index != SIZE_MAX) {
1550 if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
15641551 break;
1565 }
15661552 }
1567 size_t next_abi_align = (next_src_field_index == field_count) ?
1568 abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
1553 size_t next_abi_align;
1554 if (next_src_field_index == field_count) {
1555 next_abi_align = abi_align;
1556 } else {
1557 next_abi_align = max(fields[next_src_field_index].align,
1558 struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align);
1559 }
15691560 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);
15701561 }
15711562
......@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26532644
26542645 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26552646
2656 fn_entry->codegen = g;
26572647 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
26582648 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
26592649 fn_entry->analyzed_executable.fn_entry = fn_entry;
......@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
27812771 }
27822772 }
27832773 } else {
2774 fn_table_entry->inferred_async_node = inferred_async_none;
27842775 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
27852776 }
27862777
......@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
28022793 g->fn_defs.append(fn_table_entry);
28032794 }
28042795
2796 // if the calling convention implies that it cannot be async, we save that for later
2797 // and leave the value to be nullptr to indicate that we have not emitted possible
2798 // compile errors for improperly calling async functions.
2799 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
2800 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
2801 }
2802
28052803 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
28062804 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
28072805 {
......@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
30353033 case NodeTypeIfErrorExpr:
30363034 case NodeTypeIfOptional:
30373035 case NodeTypeErrorSetDecl:
3038 case NodeTypeCancel:
30393036 case NodeTypeResume:
30403037 case NodeTypeAwaitExpr:
30413038 case NodeTypeSuspend:
3042 case NodeTypePromiseType:
30433039 case NodeTypeEnumLiteral:
3040 case NodeTypeAnyFrameType:
30443041 zig_unreachable();
30453042 }
30463043}
......@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
30913088 case ZigTypeIdUnion:
30923089 case ZigTypeIdFn:
30933090 case ZigTypeIdBoundFn:
3094 case ZigTypeIdPromise:
30953091 case ZigTypeIdVector:
3092 case ZigTypeIdFnFrame:
3093 case ZigTypeIdAnyFrame:
30963094 return type_entry;
30973095 }
30983096 zig_unreachable();
......@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {
35923590 case ZigTypeIdBoundFn:
35933591 case ZigTypeIdArgTuple:
35943592 case ZigTypeIdOpaque:
3595 case ZigTypeIdPromise:
35963593 case ZigTypeIdVector:
3594 case ZigTypeIdFnFrame:
3595 case ZigTypeIdAnyFrame:
35973596 return false;
35983597 }
35993598 zig_unreachable();
......@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
36493648 case ZigTypeIdInvalid:
36503649 case ZigTypeIdArgTuple:
36513650 case ZigTypeIdOpaque:
3652 case ZigTypeIdPromise:
36533651 case ZigTypeIdVector:
3652 case ZigTypeIdFnFrame:
3653 case ZigTypeIdAnyFrame:
36543654 zig_unreachable();
36553655 }
36563656 zig_unreachable();
......@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
36593659ZigType *get_src_ptr_type(ZigType *type) {
36603660 if (type->id == ZigTypeIdPointer) return type;
36613661 if (type->id == ZigTypeIdFn) return type;
3662 if (type->id == ZigTypeIdPromise) return type;
3662 if (type->id == ZigTypeIdAnyFrame) return type;
36633663 if (type->id == ZigTypeIdOptional) {
36643664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
36653665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
36663666 }
36673667 if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
3668 if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;
3668 if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type;
36693669 }
36703670 return nullptr;
36713671}
......@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {
36813681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);
36823682}
36833683
3684static uint32_t get_async_frame_align_bytes(CodeGen *g) {
3685 uint32_t a = g->pointer_size_bytes * 2;
3686 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
3687 if (a < 8) a = 8;
3688 return a;
3689}
3690
36843691uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
36853692 ZigType *ptr_type = get_src_ptr_type(type);
36863693 if (ptr_type->id == ZigTypeIdPointer) {
......@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
36923699 // when getting the alignment of `?extern fn() void`.
36933700 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html
36943701 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
3695 } else if (ptr_type->id == ZigTypeIdPromise) {
3696 return get_coro_frame_align_bytes(g);
3702 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3703 return get_async_frame_align_bytes(g);
36973704 } else {
36983705 zig_unreachable();
36993706 }
......@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {
37053712 return ptr_type->data.pointer.is_const;
37063713 } else if (ptr_type->id == ZigTypeIdFn) {
37073714 return true;
3708 } else if (ptr_type->id == ZigTypeIdPromise) {
3715 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
37093716 return true;
37103717 } else {
37113718 zig_unreachable();
......@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
37803787 return true;
37813788}
37823789
3783void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
3784 ZigType *fn_type = fn_table_entry->type_entry;
3790static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) {
3791 ZigType *frame_type = get_fn_frame_type(g, fn);
3792 Error err;
3793 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {
3794 fn->anal_state = FnAnalStateInvalid;
3795 return;
3796 }
3797}
3798
3799bool fn_is_async(ZigFn *fn) {
3800 assert(fn->inferred_async_node != nullptr);
3801 assert(fn->inferred_async_node != inferred_async_checking);
3802 return fn->inferred_async_node != inferred_async_none;
3803}
3804
3805static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3806 assert(fn->inferred_async_node != nullptr);
3807 assert(fn->inferred_async_node != inferred_async_checking);
3808 assert(fn->inferred_async_node != inferred_async_none);
3809 if (fn->inferred_async_fn != nullptr) {
3810 ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node,
3811 buf_sprintf("async function call here"));
3812 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);
3813 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {
3814 add_error_note(g, msg, fn->inferred_async_node,
3815 buf_sprintf("async calling convention here"));
3816 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {
3817 add_error_note(g, msg, fn->inferred_async_node,
3818 buf_sprintf("suspends here"));
3819 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3820 add_error_note(g, msg, fn->inferred_async_node,
3821 buf_sprintf("await is a suspend point"));
3822 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&
3823 fn->inferred_async_node->data.fn_call_expr.is_builtin)
3824 {
3825 add_error_note(g, msg, fn->inferred_async_node,
3826 buf_sprintf("@frame() causes function to be async"));
3827 } else {
3828 add_error_note(g, msg, fn->inferred_async_node,
3829 buf_sprintf("suspends here"));
3830 }
3831}
3832
3833// This function resolves functions being inferred async.
3834static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
3835 if (fn->inferred_async_node == inferred_async_checking) {
3836 // TODO call graph cycle detected, disallow the recursion
3837 fn->inferred_async_node = inferred_async_none;
3838 return;
3839 }
3840 if (fn->inferred_async_node == inferred_async_none) {
3841 return;
3842 }
3843 if (fn->inferred_async_node != nullptr) {
3844 if (resolve_frame) {
3845 resolve_async_fn_frame(g, fn);
3846 }
3847 return;
3848 }
3849 fn->inferred_async_node = inferred_async_checking;
3850
3851 bool must_not_be_async = false;
3852 if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) {
3853 must_not_be_async = true;
3854 fn->inferred_async_node = inferred_async_none;
3855 }
3856
3857 for (size_t i = 0; i < fn->call_list.length; i += 1) {
3858 IrInstructionCallGen *call = fn->call_list.at(i);
3859 ZigFn *callee = call->fn_entry;
3860 if (callee == nullptr) {
3861 // TODO function pointer call here, could be anything
3862 continue;
3863 }
3864
3865 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
3866 continue;
3867 if (callee->anal_state == FnAnalStateReady) {
3868 analyze_fn_body(g, callee);
3869 if (callee->anal_state == FnAnalStateInvalid) {
3870 fn->anal_state = FnAnalStateInvalid;
3871 return;
3872 }
3873 }
3874 assert(callee->anal_state == FnAnalStateComplete);
3875 analyze_fn_async(g, callee, true);
3876 if (callee->anal_state == FnAnalStateInvalid) {
3877 fn->anal_state = FnAnalStateInvalid;
3878 return;
3879 }
3880 if (fn_is_async(callee)) {
3881 fn->inferred_async_node = call->base.source_node;
3882 fn->inferred_async_fn = callee;
3883 if (must_not_be_async) {
3884 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3885 buf_sprintf("function with calling convention '%s' cannot be async",
3886 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
3887 add_async_error_notes(g, msg, fn);
3888 fn->anal_state = FnAnalStateInvalid;
3889 return;
3890 }
3891 if (resolve_frame) {
3892 resolve_async_fn_frame(g, fn);
3893 }
3894 return;
3895 }
3896 }
3897 fn->inferred_async_node = inferred_async_none;
3898}
3899
3900static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
3901 ZigType *fn_type = fn->type_entry;
37853902 assert(!fn_type->data.fn.is_generic);
37863903 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
37873904
3788 ZigType *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
3789 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
3790 fn_table_entry->src_implicit_return_type = block_return_type;
3905 ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,
3906 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
3907 fn->src_implicit_return_type = block_return_type;
37913908
3792 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3909 if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) {
37933910 assert(g->errors.length > 0);
3794 fn_table_entry->anal_state = FnAnalStateInvalid;
3911 fn->anal_state = FnAnalStateInvalid;
37953912 return;
37963913 }
37973914
......@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
37993916 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
38003917 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
38013918 ZigType *inferred_err_set_type;
3802 if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3803 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3804 } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3805 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
3919 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3920 inferred_err_set_type = fn->src_implicit_return_type;
3921 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3922 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
38063923 } else {
38073924 add_node_error(g, return_type_node,
38083925 buf_sprintf("function with inferred error set must return at least one possible error"));
3809 fn_table_entry->anal_state = FnAnalStateInvalid;
3926 fn->anal_state = FnAnalStateInvalid;
38103927 return;
38113928 }
38123929
38133930 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
38143931 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
3815 fn_table_entry->anal_state = FnAnalStateInvalid;
3932 fn->anal_state = FnAnalStateInvalid;
38163933 return;
38173934 }
38183935 }
......@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
38323949 }
38333950 }
38343951
3952 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
3953 if (cc != CallingConventionUnspecified && cc != CallingConventionAsync &&
3954 fn->inferred_async_node != nullptr &&
3955 fn->inferred_async_node != inferred_async_checking &&
3956 fn->inferred_async_node != inferred_async_none)
3957 {
3958 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3959 buf_sprintf("function with calling convention '%s' cannot be async",
3960 calling_convention_name(cc)));
3961 add_async_error_notes(g, msg, fn);
3962 fn->anal_state = FnAnalStateInvalid;
3963 }
3964
38353965 if (g->verbose_ir) {
3836 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
3837 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
3966 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
3967 ir_print(g, stderr, &fn->analyzed_executable, 4);
38383968 fprintf(stderr, "}\n");
38393969 }
3840
3841 fn_table_entry->anal_state = FnAnalStateComplete;
3970 fn->anal_state = FnAnalStateComplete;
38423971}
38433972
38443973static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
......@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {
40084137 analyze_fn_body(g, fn_entry);
40094138 }
40104139 }
4140
4141 if (g->errors.length != 0) {
4142 return;
4143 }
4144
4145 // second pass over functions for detecting async
4146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
4147 ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);
4148 analyze_fn_async(g, fn_entry, true);
4149 }
40114150}
40124151
40134152ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
......@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {
41034242 case ZigTypeIdErrorSet:
41044243 case ZigTypeIdFn:
41054244 case ZigTypeIdEnum:
4106 case ZigTypeIdPromise:
41074245 case ZigTypeIdVector:
4246 case ZigTypeIdAnyFrame:
41084247 return false;
41094248 case ZigTypeIdArray:
41104249 case ZigTypeIdStruct:
4250 case ZigTypeIdFnFrame:
41114251 return type_has_bits(type_entry);
41124252 case ZigTypeIdErrorUnion:
41134253 return type_has_bits(type_entry->data.error_union.payload_type);
......@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
41434283 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
41444284 result += id->is_var_args ? (uint32_t)1931444534 : 0;
41454285 result += hash_ptr(id->return_type);
4146 result += hash_ptr(id->async_allocator_type);
41474286 result += id->alignment * 0xd3b3f3e2;
41484287 for (size_t i = 0; i < id->param_count; i += 1) {
41494288 FnTypeParamInfo *info = &id->param_info[i];
......@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
41584297 a->return_type != b->return_type ||
41594298 a->is_var_args != b->is_var_args ||
41604299 a->param_count != b->param_count ||
4161 a->alignment != b->alignment ||
4162 a->async_allocator_type != b->async_allocator_type)
4300 a->alignment != b->alignment)
41634301 {
41644302 return false;
41654303 }
......@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43214459 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
43224460 case ZigTypeIdPointer:
43234461 return hash_const_val_ptr(const_val);
4324 case ZigTypeIdPromise:
4325 // TODO better hashing algorithm
4326 return 223048345;
43274462 case ZigTypeIdUndefined:
43284463 return 162837799;
43294464 case ZigTypeIdNull:
......@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43574492 case ZigTypeIdVector:
43584493 // TODO better hashing algorithm
43594494 return 3647867726;
4495 case ZigTypeIdFnFrame:
4496 // TODO better hashing algorithm
4497 return 675741936;
4498 case ZigTypeIdAnyFrame:
4499 // TODO better hashing algorithm
4500 return 3747294894;
43604501 case ZigTypeIdBoundFn:
43614502 case ZigTypeIdInvalid:
43624503 case ZigTypeIdUnreachable:
......@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
43894530 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
43904531 assert(a_val->special == ConstValSpecialStatic);
43914532 assert(b_val->special == ConstValSpecialStatic);
4392 if (!const_values_equal(a->fn_entry->codegen, a_val, b_val)) {
4533 if (!const_values_equal(a->codegen, a_val, b_val)) {
43934534 return false;
43944535 }
43954536 } else {
......@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
44194560 case ZigTypeIdBoundFn:
44204561 case ZigTypeIdFn:
44214562 case ZigTypeIdOpaque:
4422 case ZigTypeIdPromise:
44234563 case ZigTypeIdErrorSet:
44244564 case ZigTypeIdEnum:
4565 case ZigTypeIdFnFrame:
4566 case ZigTypeIdAnyFrame:
44254567 return false;
44264568
44274569 case ZigTypeIdPointer:
......@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {
44894631 case ZigTypeIdBoundFn:
44904632 case ZigTypeIdFn:
44914633 case ZigTypeIdOpaque:
4492 case ZigTypeIdPromise:
44934634 case ZigTypeIdErrorSet:
44944635 case ZigTypeIdEnum:
44954636 case ZigTypeIdPointer:
44964637 case ZigTypeIdVector:
4638 case ZigTypeIdFnFrame:
4639 case ZigTypeIdAnyFrame:
44974640 return true;
44984641
44994642 case ZigTypeIdArray:
......@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
46244767 case ZigTypeIdFn:
46254768 case ZigTypeIdBool:
46264769 case ZigTypeIdFloat:
4627 case ZigTypeIdPromise:
46284770 case ZigTypeIdErrorUnion:
4771 case ZigTypeIdFnFrame:
4772 case ZigTypeIdAnyFrame:
46294773 return OnePossibleValueNo;
46304774 case ZigTypeIdUndefined:
46314775 case ZigTypeIdNull:
......@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
47134857 case ZigTypeIdFloat:
47144858 case ZigTypeIdVoid:
47154859 case ZigTypeIdUnreachable:
4716 case ZigTypeIdPromise:
4860 case ZigTypeIdFnFrame:
4861 case ZigTypeIdAnyFrame:
47174862 return ReqCompTimeNo;
47184863 }
47194864 zig_unreachable();
......@@ -5032,6 +5177,221 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
50325177 return type_resolve(g, type_entry, ResolveStatusSizeKnown);
50335178}
50345179
5180static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
5181 if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync)
5182 return orig_fn_type;
5183
5184 ZigType *fn_type = allocate_nonzero<ZigType>(1);
5185 *fn_type = *orig_fn_type;
5186 fn_type->data.fn.fn_type_id.cc = CallingConventionAsync;
5187 fn_type->llvm_type = nullptr;
5188 fn_type->llvm_di_type = nullptr;
5189
5190 return fn_type;
5191}
5192
5193static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5194 Error err;
5195
5196 if (frame_type->data.frame.locals_struct != nullptr)
5197 return ErrorNone;
5198
5199 ZigFn *fn = frame_type->data.frame.fn;
5200 switch (fn->anal_state) {
5201 case FnAnalStateInvalid:
5202 return ErrorSemanticAnalyzeFail;
5203 case FnAnalStateComplete:
5204 break;
5205 case FnAnalStateReady:
5206 analyze_fn_body(g, fn);
5207 if (fn->anal_state == FnAnalStateInvalid)
5208 return ErrorSemanticAnalyzeFail;
5209 break;
5210 case FnAnalStateProbing: {
5211 ErrorMsg *msg = add_node_error(g, fn->proto_node,
5212 buf_sprintf("cannot resolve '%s': function not fully analyzed yet",
5213 buf_ptr(&frame_type->name)));
5214 ir_add_analysis_trace(fn->ir_executable.analysis, msg,
5215 buf_sprintf("depends on its own frame here"));
5216 return ErrorSemanticAnalyzeFail;
5217 }
5218 }
5219 analyze_fn_async(g, fn, false);
5220 if (fn->anal_state == FnAnalStateInvalid)
5221 return ErrorSemanticAnalyzeFail;
5222
5223 if (!fn_is_async(fn)) {
5224 ZigType *fn_type = fn->type_entry;
5225 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5226 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5227
5228 // label (grep this): [fn_frame_struct_layout]
5229 ZigList<SrcField> fields = {};
5230
5231 fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0});
5232 fields.append({"@resume_index", g->builtin_types.entry_usize, 0});
5233 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
5234
5235 fields.append({"@result_ptr_callee", ptr_return_type, 0});
5236 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
5237 fields.append({"@result", fn_type_id->return_type, 0});
5238
5239 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
5240 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
5241 fields.append({"@ptr_stack_trace_callee", ptr_to_stack_trace_type, 0});
5242 fields.append({"@ptr_stack_trace_awaiter", ptr_to_stack_trace_type, 0});
5243
5244 fields.append({"@stack_trace", get_stack_trace_type(g), 0});
5245 fields.append({"@instruction_addresses",
5246 get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
5247 }
5248
5249 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5250 fields.items, fields.length, target_fn_align(g->zig_target));
5251 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5252 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5253 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5254
5255 return ErrorNone;
5256 }
5257
5258 ZigType *fn_type = get_async_fn_type(g, fn->type_entry);
5259
5260 if (fn->analyzed_executable.need_err_code_spill) {
5261 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5262 alloca_gen->base.id = IrInstructionIdAllocaGen;
5263 alloca_gen->base.source_node = fn->proto_node;
5264 alloca_gen->base.scope = fn->child_scope;
5265 alloca_gen->base.value.type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
5266 alloca_gen->base.ref_count = 1;
5267 alloca_gen->name_hint = "";
5268 fn->alloca_gen_list.append(alloca_gen);
5269 fn->err_code_spill = &alloca_gen->base;
5270 }
5271
5272 for (size_t i = 0; i < fn->call_list.length; i += 1) {
5273 IrInstructionCallGen *call = fn->call_list.at(i);
5274 ZigFn *callee = call->fn_entry;
5275 if (callee == nullptr) {
5276 add_node_error(g, call->base.source_node,
5277 buf_sprintf("function is not comptime-known; @asyncCall required"));
5278 return ErrorSemanticAnalyzeFail;
5279 }
5280 if (callee->body_node == nullptr) {
5281 continue;
5282 }
5283 if (callee->anal_state == FnAnalStateProbing) {
5284 ErrorMsg *msg = add_node_error(g, fn->proto_node,
5285 buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name)));
5286 ErrorMsg *note = add_error_note(g, msg, call->base.source_node,
5287 buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name)));
5288 ir_add_analysis_trace(callee->ir_executable.analysis, note,
5289 buf_sprintf("depends on the frame here"));
5290 return ErrorSemanticAnalyzeFail;
5291 }
5292
5293 analyze_fn_body(g, callee);
5294 if (callee->anal_state == FnAnalStateInvalid) {
5295 frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
5296 return ErrorSemanticAnalyzeFail;
5297 }
5298 analyze_fn_async(g, callee, true);
5299 if (!fn_is_async(callee))
5300 continue;
5301
5302 ZigType *callee_frame_type = get_fn_frame_type(g, callee);
5303
5304 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5305 alloca_gen->base.id = IrInstructionIdAllocaGen;
5306 alloca_gen->base.source_node = call->base.source_node;
5307 alloca_gen->base.scope = call->base.scope;
5308 alloca_gen->base.value.type = get_pointer_to_type(g, callee_frame_type, false);
5309 alloca_gen->base.ref_count = 1;
5310 alloca_gen->name_hint = "";
5311 fn->alloca_gen_list.append(alloca_gen);
5312 call->frame_result_loc = &alloca_gen->base;
5313 }
5314 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5315 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5316
5317 // label (grep this): [fn_frame_struct_layout]
5318 ZigList<SrcField> fields = {};
5319
5320 fields.append({"@fn_ptr", fn_type, 0});
5321 fields.append({"@resume_index", g->builtin_types.entry_usize, 0});
5322 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
5323
5324 fields.append({"@result_ptr_callee", ptr_return_type, 0});
5325 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
5326 fields.append({"@result", fn_type_id->return_type, 0});
5327
5328 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
5329 ZigType *ptr_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
5330 fields.append({"@ptr_stack_trace_callee", ptr_stack_trace_type, 0});
5331 fields.append({"@ptr_stack_trace_awaiter", ptr_stack_trace_type, 0});
5332 }
5333
5334 for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) {
5335 FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i];
5336 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
5337 Buf *param_name;
5338 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
5339 if (param_decl_node && !is_var_args) {
5340 param_name = param_decl_node->data.param_decl.name;
5341 } else {
5342 param_name = buf_sprintf("@arg%" ZIG_PRI_usize, arg_i);
5343 }
5344 ZigType *param_type = param_info->type;
5345
5346 fields.append({buf_ptr(param_name), param_type, 0});
5347 }
5348
5349 if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) {
5350 fields.append({"@stack_trace", get_stack_trace_type(g), 0});
5351 fields.append({"@instruction_addresses",
5352 get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
5353 }
5354
5355 for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
5356 IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
5357 instruction->field_index = SIZE_MAX;
5358 ZigType *ptr_type = instruction->base.value.type;
5359 assert(ptr_type->id == ZigTypeIdPointer);
5360 ZigType *child_type = ptr_type->data.pointer.child_type;
5361 if (!type_has_bits(child_type))
5362 continue;
5363 if (instruction->base.ref_count == 0)
5364 continue;
5365 if (instruction->base.value.special != ConstValSpecialRuntime) {
5366 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
5367 ConstValSpecialRuntime)
5368 {
5369 continue;
5370 }
5371 }
5372 if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
5373 return err;
5374 }
5375 const char *name;
5376 if (*instruction->name_hint == 0) {
5377 name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i));
5378 } else {
5379 name = buf_ptr(buf_sprintf("%s.%" ZIG_PRI_usize, instruction->name_hint, alloca_i));
5380 }
5381 instruction->field_index = fields.length;
5382
5383 fields.append({name, child_type, instruction->align});
5384 }
5385
5386
5387 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5388 fields.items, fields.length, target_fn_align(g->zig_target));
5389 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5390 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5391 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5392 return ErrorNone;
5393}
5394
50355395Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50365396 if (type_is_invalid(ty))
50375397 return ErrorSemanticAnalyzeFail;
......@@ -5056,6 +5416,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50565416 return resolve_enum_zero_bits(g, ty);
50575417 } else if (ty->id == ZigTypeIdUnion) {
50585418 return resolve_union_alignment(g, ty);
5419 } else if (ty->id == ZigTypeIdFnFrame) {
5420 return resolve_async_frame(g, ty);
50595421 }
50605422 return ErrorNone;
50615423 case ResolveStatusSizeKnown:
......@@ -5065,6 +5427,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50655427 return resolve_enum_zero_bits(g, ty);
50665428 } else if (ty->id == ZigTypeIdUnion) {
50675429 return resolve_union_type(g, ty);
5430 } else if (ty->id == ZigTypeIdFnFrame) {
5431 return resolve_async_frame(g, ty);
50685432 }
50695433 return ErrorNone;
50705434 case ResolveStatusLLVMFwdDecl:
......@@ -5259,6 +5623,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
52595623 return false;
52605624 }
52615625 return true;
5626 case ZigTypeIdFnFrame:
5627 zig_panic("TODO");
5628 case ZigTypeIdAnyFrame:
5629 zig_panic("TODO");
52625630 case ZigTypeIdUndefined:
52635631 zig_panic("TODO");
52645632 case ZigTypeIdNull:
......@@ -5279,7 +5647,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
52795647 case ZigTypeIdBoundFn:
52805648 case ZigTypeIdInvalid:
52815649 case ZigTypeIdUnreachable:
5282 case ZigTypeIdPromise:
52835650 zig_unreachable();
52845651 }
52855652 zig_unreachable();
......@@ -5612,8 +5979,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
56125979 buf_appendf(buf, "(args value)");
56135980 return;
56145981 }
5615 case ZigTypeIdPromise:
5616 zig_unreachable();
5982 case ZigTypeIdFnFrame:
5983 buf_appendf(buf, "(TODO: async function frame value)");
5984 return;
5985
5986 case ZigTypeIdAnyFrame:
5987 buf_appendf(buf, "(TODO: anyframe value)");
5988 return;
5989
56175990 }
56185991 zig_unreachable();
56195992}
......@@ -5627,6 +6000,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
56276000 entry->llvm_type = LLVMIntType(size_in_bits);
56286001 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
56296002 entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
6003
6004 if (size_in_bits >= 128) {
6005 // Override the incorrect alignment reported by LLVM. Clang does this as well.
6006 // On x86_64 there are some instructions like CMPXCHG16B which require this.
6007 // On all targets, integers 128 bits and above have ABI alignment of 16.
6008 // See: https://github.com/ziglang/zig/issues/2987
6009 assert(entry->abi_align == 8); // if this trips we can remove the workaround
6010 entry->abi_align = 16;
6011 }
56306012 }
56316013
56326014 const char u_or_i = is_signed ? 'i' : 'u';
......@@ -5660,7 +6042,8 @@ uint32_t type_id_hash(TypeId x) {
56606042 case ZigTypeIdFn:
56616043 case ZigTypeIdBoundFn:
56626044 case ZigTypeIdArgTuple:
5663 case ZigTypeIdPromise:
6045 case ZigTypeIdFnFrame:
6046 case ZigTypeIdAnyFrame:
56646047 zig_unreachable();
56656048 case ZigTypeIdErrorUnion:
56666049 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
......@@ -5702,7 +6085,6 @@ bool type_id_eql(TypeId a, TypeId b) {
57026085 case ZigTypeIdUndefined:
57036086 case ZigTypeIdNull:
57046087 case ZigTypeIdOptional:
5705 case ZigTypeIdPromise:
57066088 case ZigTypeIdErrorSet:
57076089 case ZigTypeIdEnum:
57086090 case ZigTypeIdUnion:
......@@ -5710,6 +6092,8 @@ bool type_id_eql(TypeId a, TypeId b) {
57106092 case ZigTypeIdBoundFn:
57116093 case ZigTypeIdArgTuple:
57126094 case ZigTypeIdOpaque:
6095 case ZigTypeIdFnFrame:
6096 case ZigTypeIdAnyFrame:
57136097 zig_unreachable();
57146098 case ZigTypeIdErrorUnion:
57156099 return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&
......@@ -5875,7 +6259,8 @@ static const ZigTypeId all_type_ids[] = {
58756259 ZigTypeIdBoundFn,
58766260 ZigTypeIdArgTuple,
58776261 ZigTypeIdOpaque,
5878 ZigTypeIdPromise,
6262 ZigTypeIdFnFrame,
6263 ZigTypeIdAnyFrame,
58796264 ZigTypeIdVector,
58806265 ZigTypeIdEnumLiteral,
58816266};
......@@ -5939,12 +6324,14 @@ size_t type_id_index(ZigType *entry) {
59396324 return 20;
59406325 case ZigTypeIdOpaque:
59416326 return 21;
5942 case ZigTypeIdPromise:
6327 case ZigTypeIdFnFrame:
59436328 return 22;
5944 case ZigTypeIdVector:
6329 case ZigTypeIdAnyFrame:
59456330 return 23;
5946 case ZigTypeIdEnumLiteral:
6331 case ZigTypeIdVector:
59476332 return 24;
6333 case ZigTypeIdEnumLiteral:
6334 return 25;
59486335 }
59496336 zig_unreachable();
59506337}
......@@ -5999,10 +6386,12 @@ const char *type_id_name(ZigTypeId id) {
59996386 return "ArgTuple";
60006387 case ZigTypeIdOpaque:
60016388 return "Opaque";
6002 case ZigTypeIdPromise:
6003 return "Promise";
60046389 case ZigTypeIdVector:
60056390 return "Vector";
6391 case ZigTypeIdFnFrame:
6392 return "Frame";
6393 case ZigTypeIdAnyFrame:
6394 return "AnyFrame";
60066395 }
60076396 zig_unreachable();
60086397}
......@@ -6067,19 +6456,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {
60676456 return err_set_type->data.error_set.err_count == UINT32_MAX;
60686457}
60696458
6070uint32_t get_coro_frame_align_bytes(CodeGen *g) {
6071 uint32_t a = g->pointer_size_bytes * 2;
6072 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
6073 if (a < 8) a = 8;
6074 return a;
6075}
6076
60776459bool type_can_fail(ZigType *type_entry) {
60786460 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;
60796461}
60806462
60816463bool fn_type_can_fail(FnTypeId *fn_type_id) {
6082 return type_can_fail(fn_type_id->return_type) || fn_type_id->cc == CallingConventionAsync;
6464 return type_can_fail(fn_type_id->return_type);
60836465}
60846466
60856467// ErrorNone - result pointer has the type
......@@ -6449,7 +6831,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
64496831 type->data.structure.resolve_status = ResolveStatusLLVMFull;
64506832}
64516833
6452static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status) {
6834static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status,
6835 ZigType *async_frame_type)
6836{
64536837 assert(struct_type->id == ZigTypeIdStruct);
64546838 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);
64556839 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);
......@@ -6486,10 +6870,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64866870 }
64876871
64886872 size_t field_count = struct_type->data.structure.src_field_count;
6489 size_t gen_field_count = struct_type->data.structure.gen_field_count;
6490 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
6873 // Every field could potentially have a generated padding field after it.
6874 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count * 2);
64916875
6492 size_t gen_field_index = 0;
64936876 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
64946877 size_t packed_bits_offset = 0;
64956878 size_t first_packed_bits_offset_misalign = SIZE_MAX;
......@@ -6497,20 +6880,36 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64976880
64986881 // trigger all the recursive get_llvm_type calls
64996882 for (size_t i = 0; i < field_count; i += 1) {
6500 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6501 ZigType *field_type = type_struct_field->type_entry;
6883 TypeStructField *field = &struct_type->data.structure.fields[i];
6884 ZigType *field_type = field->type_entry;
65026885 if (!type_has_bits(field_type))
65036886 continue;
65046887 (void)get_llvm_type(g, field_type);
65056888 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;
65066889 }
65076890
6508 for (size_t i = 0; i < field_count; i += 1) {
6509 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6510 ZigType *field_type = type_struct_field->type_entry;
6891 size_t gen_field_index = 0;
65116892
6893 // Calculate what LLVM thinks the ABI align of the struct will be. We do this to avoid
6894 // inserting padding bytes where LLVM would do it automatically.
6895 size_t llvm_struct_abi_align = 0;
6896 for (size_t i = 0; i < field_count; i += 1) {
6897 ZigType *field_type = struct_type->data.structure.fields[i].type_entry;
65126898 if (!type_has_bits(field_type))
65136899 continue;
6900 LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type);
6901 size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type);
6902 llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align);
6903 }
6904
6905 for (size_t i = 0; i < field_count; i += 1) {
6906 TypeStructField *field = &struct_type->data.structure.fields[i];
6907 ZigType *field_type = field->type_entry;
6908
6909 if (!type_has_bits(field_type)) {
6910 field->gen_index = SIZE_MAX;
6911 continue;
6912 }
65146913
65156914 if (packed) {
65166915 size_t field_size_in_bits = type_size_bits(g, field_type);
......@@ -6537,12 +6936,61 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65376936 }
65386937 packed_bits_offset = next_packed_bits_offset;
65396938 } else {
6540 element_types[gen_field_index] = get_llvm_type(g, field_type);
6541
6939 LLVMTypeRef llvm_type;
6940 if (i == 0 && async_frame_type != nullptr) {
6941 assert(async_frame_type->id == ZigTypeIdFnFrame);
6942 assert(field_type->id == ZigTypeIdFn);
6943 resolve_llvm_types_fn(g, async_frame_type->data.frame.fn);
6944 llvm_type = LLVMPointerType(async_frame_type->data.frame.fn->raw_type_ref, 0);
6945 } else {
6946 llvm_type = get_llvm_type(g, field_type);
6947 }
6948 element_types[gen_field_index] = llvm_type;
6949 field->gen_index = gen_field_index;
65426950 gen_field_index += 1;
6951
6952 // find the next non-zero-byte field for offset calculations
6953 size_t next_src_field_index = i + 1;
6954 for (; next_src_field_index < field_count; next_src_field_index += 1) {
6955 if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
6956 break;
6957 }
6958 size_t next_abi_align;
6959 if (next_src_field_index == field_count) {
6960 next_abi_align = struct_type->abi_align;
6961 } else {
6962 if (struct_type->data.structure.fields[next_src_field_index].align == 0) {
6963 next_abi_align = struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
6964 } else {
6965 next_abi_align = struct_type->data.structure.fields[next_src_field_index].align;
6966 }
6967 }
6968 size_t llvm_next_abi_align = (next_src_field_index == field_count) ?
6969 llvm_struct_abi_align :
6970 LLVMABIAlignmentOfType(g->target_data_ref,
6971 get_llvm_type(g, struct_type->data.structure.fields[next_src_field_index].type_entry));
6972
6973 size_t next_offset = next_field_offset(field->offset, struct_type->abi_align,
6974 field_type->abi_size, next_abi_align);
6975 size_t llvm_next_offset = next_field_offset(field->offset, llvm_struct_abi_align,
6976 LLVMABISizeOfType(g->target_data_ref, llvm_type), llvm_next_abi_align);
6977
6978 assert(next_offset >= llvm_next_offset);
6979 if (next_offset > llvm_next_offset) {
6980 size_t pad_bytes = next_offset - (field->offset + field_type->abi_size);
6981 if (pad_bytes != 0) {
6982 LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
6983 element_types[gen_field_index] = pad_llvm_type;
6984 gen_field_index += 1;
6985 }
6986 }
65436987 }
65446988 debug_field_count += 1;
65456989 }
6990 if (!packed) {
6991 struct_type->data.structure.gen_field_count = gen_field_index;
6992 }
6993
65466994 if (first_packed_bits_offset_misalign != SIZE_MAX) {
65476995 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
65486996 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
......@@ -6551,19 +6999,20 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65516999 }
65527000
65537001 if (type_has_bits(struct_type)) {
6554 LLVMStructSetBody(struct_type->llvm_type, element_types, (unsigned)gen_field_count, packed);
7002 LLVMStructSetBody(struct_type->llvm_type, element_types,
7003 (unsigned)struct_type->data.structure.gen_field_count, packed);
65557004 }
65567005
65577006 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
65587007 size_t debug_field_index = 0;
65597008 for (size_t i = 0; i < field_count; i += 1) {
6560 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6561 size_t gen_field_index = type_struct_field->gen_index;
7009 TypeStructField *field = &struct_type->data.structure.fields[i];
7010 size_t gen_field_index = field->gen_index;
65627011 if (gen_field_index == SIZE_MAX) {
65637012 continue;
65647013 }
65657014
6566 ZigType *field_type = type_struct_field->type_entry;
7015 ZigType *field_type = field->type_entry;
65677016
65687017 // if the field is a function, actually the debug info should be a pointer.
65697018 ZigLLVMDIType *field_di_type;
......@@ -6581,13 +7030,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65817030 uint64_t debug_align_in_bits;
65827031 uint64_t debug_offset_in_bits;
65837032 if (packed) {
6584 debug_size_in_bits = type_struct_field->type_entry->size_in_bits;
6585 debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;
6586 debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;
7033 debug_size_in_bits = field->type_entry->size_in_bits;
7034 debug_align_in_bits = 8 * field->type_entry->abi_align;
7035 debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host;
65877036 } else {
65887037 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);
65897038 debug_align_in_bits = 8 * field_type->abi_align;
6590 debug_offset_in_bits = 8 * type_struct_field->offset;
7039 debug_offset_in_bits = 8 * field->offset;
65917040 }
65927041 unsigned line;
65937042 if (decl_node != nullptr) {
......@@ -6597,7 +7046,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65977046 line = 0;
65987047 }
65997048 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
6600 ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(type_struct_field->name),
7049 ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(field->name),
66017050 di_file, line,
66027051 debug_size_in_bits,
66037052 debug_align_in_bits,
......@@ -6838,7 +7287,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
68387287 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
68397288}
68407289
6841static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
7290static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
68427291 if (type->llvm_di_type != nullptr) return;
68437292
68447293 if (!type_has_bits(type)) {
......@@ -6867,7 +7316,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
68677316 uint64_t debug_align_in_bits = 8*type->abi_align;
68687317 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,
68697318 debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));
6870 assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFull));
7319 assertNoError(type_resolve(g, elem_type, wanted_resolve_status));
68717320 } else {
68727321 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
68737322 LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);
......@@ -6993,10 +7442,17 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
69937442 } else {
69947443 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
69957444 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
6996 LLVMTypeRef elem_types[2];
7445 LLVMTypeRef elem_types[3];
69977446 elem_types[err_union_err_index] = err_set_llvm_type;
69987447 elem_types[err_union_payload_index] = payload_llvm_type;
7448
69997449 type->llvm_type = LLVMStructType(elem_types, 2, false);
7450 if (LLVMABISizeOfType(g->target_data_ref, type->llvm_type) != type->abi_size) {
7451 // we need to do our own padding
7452 type->data.error_union.pad_llvm_type = LLVMArrayType(LLVMInt8Type(), type->data.error_union.pad_bytes);
7453 elem_types[2] = type->data.error_union.pad_llvm_type;
7454 type->llvm_type = LLVMStructType(elem_types, 3, false);
7455 }
70007456
70017457 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
70027458 ZigLLVMDIFile *di_file = nullptr;
......@@ -7068,7 +7524,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
70687524 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
70697525}
70707526
7071static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7527static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
70727528 if (fn_type->llvm_di_type != nullptr) return;
70737529
70747530 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -7085,67 +7541,73 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
70857541 // +1 for maybe first argument the error return trace
70867542 // +2 for maybe arguments async allocator and error code pointer
70877543 ZigList<ZigLLVMDIType *> param_di_types = {};
7088 param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
70897544 ZigType *gen_return_type;
70907545 if (is_async) {
7091 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
7546 gen_return_type = g->builtin_types.entry_void;
7547 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70927548 } else if (!type_has_bits(fn_type_id->return_type)) {
70937549 gen_return_type = g->builtin_types.entry_void;
7550 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70947551 } else if (first_arg_return) {
7552 gen_return_type = g->builtin_types.entry_void;
7553 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70957554 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
70967555 gen_param_types.append(get_llvm_type(g, gen_type));
70977556 param_di_types.append(get_llvm_di_type(g, gen_type));
7098 gen_return_type = g->builtin_types.entry_void;
70997557 } else {
71007558 gen_return_type = fn_type_id->return_type;
7559 param_di_types.append(get_llvm_di_type(g, gen_return_type));
71017560 }
71027561 fn_type->data.fn.gen_return_type = gen_return_type;
71037562
7104 if (prefix_arg_error_return_trace) {
7105 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
7563 if (prefix_arg_error_return_trace && !is_async) {
7564 ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
71067565 gen_param_types.append(get_llvm_type(g, gen_type));
71077566 param_di_types.append(get_llvm_di_type(g, gen_type));
71087567 }
71097568 if (is_async) {
7110 {
7111 // async allocator param
7112 ZigType *gen_type = fn_type_id->async_allocator_type;
7113 gen_param_types.append(get_llvm_type(g, gen_type));
7114 param_di_types.append(get_llvm_di_type(g, gen_type));
7115 }
7569 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(2);
71167570
7117 {
7118 // error code pointer
7119 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
7120 gen_param_types.append(get_llvm_type(g, gen_type));
7121 param_di_types.append(get_llvm_di_type(g, gen_type));
7122 }
7123 }
7571 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7572 gen_param_types.append(get_llvm_type(g, frame_type));
7573 param_di_types.append(get_llvm_di_type(g, frame_type));
71247574
7125 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7126 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
7127 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
7128 ZigType *type_entry = src_param_info->type;
7129 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
7575 fn_type->data.fn.gen_param_info[0].src_index = 0;
7576 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7577 fn_type->data.fn.gen_param_info[0].type = frame_type;
71307578
7131 gen_param_info->src_index = i;
7132 gen_param_info->gen_index = SIZE_MAX;
7579 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7580 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
71337581
7134 if (is_c_abi || !type_has_bits(type_entry))
7135 continue;
7582 fn_type->data.fn.gen_param_info[1].src_index = 1;
7583 fn_type->data.fn.gen_param_info[1].gen_index = 1;
7584 fn_type->data.fn.gen_param_info[1].type = g->builtin_types.entry_usize;
7585 } else {
7586 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7587 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
7588 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
7589 ZigType *type_entry = src_param_info->type;
7590 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
71367591
7137 ZigType *gen_type;
7138 if (handle_is_ptr(type_entry)) {
7139 gen_type = get_pointer_to_type(g, type_entry, true);
7140 gen_param_info->is_byval = true;
7141 } else {
7142 gen_type = type_entry;
7143 }
7144 gen_param_info->gen_index = gen_param_types.length;
7145 gen_param_info->type = gen_type;
7146 gen_param_types.append(get_llvm_type(g, gen_type));
7592 gen_param_info->src_index = i;
7593 gen_param_info->gen_index = SIZE_MAX;
71477594
7148 param_di_types.append(get_llvm_di_type(g, gen_type));
7595 if (is_c_abi || !type_has_bits(type_entry))
7596 continue;
7597
7598 ZigType *gen_type;
7599 if (handle_is_ptr(type_entry)) {
7600 gen_type = get_pointer_to_type(g, type_entry, true);
7601 gen_param_info->is_byval = true;
7602 } else {
7603 gen_type = type_entry;
7604 }
7605 gen_param_info->gen_index = gen_param_types.length;
7606 gen_param_info->type = gen_type;
7607 gen_param_types.append(get_llvm_type(g, gen_type));
7608
7609 param_di_types.append(get_llvm_di_type(g, gen_type));
7610 }
71497611 }
71507612
71517613 if (is_c_abi) {
......@@ -7161,6 +7623,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
71617623 for (size_t i = 0; i < gen_param_types.length; i += 1) {
71627624 assert(gen_param_types.items[i] != nullptr);
71637625 }
7626
71647627 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
71657628 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
71667629 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
......@@ -7170,6 +7633,40 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
71707633 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
71717634}
71727635
7636void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
7637 Error err;
7638 if (fn->raw_di_type != nullptr) return;
7639
7640 ZigType *fn_type = fn->type_entry;
7641 if (!fn_is_async(fn)) {
7642 resolve_llvm_types_fn_type(g, fn_type);
7643 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
7644 fn->raw_di_type = fn_type->data.fn.raw_di_type;
7645 return;
7646 }
7647
7648 ZigType *gen_return_type = g->builtin_types.entry_void;
7649 ZigList<ZigLLVMDIType *> param_di_types = {};
7650 ZigList<LLVMTypeRef> gen_param_types = {};
7651 // first "parameter" is return value
7652 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7653
7654 ZigType *frame_type = get_fn_frame_type(g, fn);
7655 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7656 if ((err = type_resolve(g, ptr_type, ResolveStatusLLVMFwdDecl)))
7657 zig_unreachable();
7658 gen_param_types.append(ptr_type->llvm_type);
7659 param_di_types.append(ptr_type->llvm_di_type);
7660
7661 // this parameter is used to pass the result pointer when await completes
7662 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7663 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
7664
7665 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7666 gen_param_types.items, gen_param_types.length, false);
7667 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7668}
7669
71737670static void resolve_llvm_types_anyerror(CodeGen *g) {
71747671 ZigType *entry = g->builtin_types.entry_global_error_set;
71757672 entry->llvm_type = get_llvm_type(g, g->err_tag_type);
......@@ -7194,6 +7691,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
71947691 get_llvm_di_type(g, g->err_tag_type), "");
71957692}
71967693
7694static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {
7695 ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;
7696 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);
7697 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
7698 frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type;
7699}
7700
7701static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, ResolveStatus wanted_resolve_status) {
7702 if (any_frame_type->llvm_di_type != nullptr) return;
7703
7704 Buf *name = buf_sprintf("(%s header)", buf_ptr(&any_frame_type->name));
7705 LLVMTypeRef frame_header_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
7706 any_frame_type->llvm_type = LLVMPointerType(frame_header_type, 0);
7707
7708 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
7709 ZigLLVMDIFile *di_file = nullptr;
7710 ZigLLVMDIScope *di_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7711 unsigned line = 0;
7712 ZigLLVMDIType *frame_header_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
7713 dwarf_kind, buf_ptr(name), di_scope, di_file, line);
7714 any_frame_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, frame_header_di_type,
7715 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name));
7716
7717 LLVMTypeRef llvm_void = LLVMVoidType();
7718 LLVMTypeRef arg_types[] = {any_frame_type->llvm_type, g->builtin_types.entry_usize->llvm_type};
7719 LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, arg_types, 2, false);
7720 LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize);
7721 ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize);
7722 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7723
7724 ZigType *result_type = any_frame_type->data.any_frame.result_type;
7725 ZigType *ptr_result_type = (result_type == nullptr) ? nullptr : get_pointer_to_type(g, result_type, false);
7726 LLVMTypeRef ptr_fn_llvm_type = LLVMPointerType(fn_type, 0);
7727 if (result_type == nullptr) {
7728 g->anyframe_fn_type = ptr_fn_llvm_type;
7729 }
7730
7731 ZigList<LLVMTypeRef> field_types = {};
7732 ZigList<ZigLLVMDIType *> di_element_types = {};
7733
7734 // label (grep this): [fn_frame_struct_layout]
7735 field_types.append(ptr_fn_llvm_type); // fn_ptr
7736 field_types.append(usize_type_ref); // resume_index
7737 field_types.append(usize_type_ref); // awaiter
7738
7739 bool have_result_type = result_type != nullptr && type_has_bits(result_type);
7740 if (have_result_type) {
7741 field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_callee
7742 field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_awaiter
7743 field_types.append(get_llvm_type(g, result_type)); // result
7744 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
7745 ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false);
7746 field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_callee
7747 field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_awaiter
7748 }
7749 }
7750 LLVMStructSetBody(frame_header_type, field_types.items, field_types.length, false);
7751
7752 di_element_types.append(
7753 ZigLLVMCreateDebugMemberType(g->dbuilder,
7754 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "fn_ptr",
7755 di_file, line,
7756 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7757 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7758 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7759 ZigLLVM_DIFlags_Zero, usize_di_type));
7760 di_element_types.append(
7761 ZigLLVMCreateDebugMemberType(g->dbuilder,
7762 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "resume_index",
7763 di_file, line,
7764 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7765 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7766 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7767 ZigLLVM_DIFlags_Zero, usize_di_type));
7768 di_element_types.append(
7769 ZigLLVMCreateDebugMemberType(g->dbuilder,
7770 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "awaiter",
7771 di_file, line,
7772 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7773 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7774 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7775 ZigLLVM_DIFlags_Zero, usize_di_type));
7776
7777 if (have_result_type) {
7778 di_element_types.append(
7779 ZigLLVMCreateDebugMemberType(g->dbuilder,
7780 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_callee",
7781 di_file, line,
7782 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7783 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7784 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7785 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type)));
7786 di_element_types.append(
7787 ZigLLVMCreateDebugMemberType(g->dbuilder,
7788 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_awaiter",
7789 di_file, line,
7790 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7791 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7792 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7793 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type)));
7794 di_element_types.append(
7795 ZigLLVMCreateDebugMemberType(g->dbuilder,
7796 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result",
7797 di_file, line,
7798 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7799 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7800 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7801 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, result_type)));
7802
7803 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
7804 ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false);
7805 di_element_types.append(
7806 ZigLLVMCreateDebugMemberType(g->dbuilder,
7807 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_callee",
7808 di_file, line,
7809 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7810 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7811 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7812 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace)));
7813 di_element_types.append(
7814 ZigLLVMCreateDebugMemberType(g->dbuilder,
7815 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_awaiter",
7816 di_file, line,
7817 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7818 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7819 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7820 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace)));
7821 }
7822 };
7823
7824 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
7825 compile_unit_scope, buf_ptr(name),
7826 di_file, line,
7827 8*LLVMABISizeOfType(g->target_data_ref, frame_header_type),
7828 8*LLVMABIAlignmentOfType(g->target_data_ref, frame_header_type),
7829 ZigLLVM_DIFlags_Zero,
7830 nullptr, di_element_types.items, di_element_types.length, 0, nullptr, "");
7831
7832 ZigLLVMReplaceTemporary(g->dbuilder, frame_header_di_type, replacement_di_type);
7833}
7834
71977835static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
71987836 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
71997837 assert(wanted_resolve_status > ResolveStatusSizeKnown);
......@@ -7219,20 +7857,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72197857 if (type->data.structure.is_slice)
72207858 return resolve_llvm_types_slice(g, type, wanted_resolve_status);
72217859 else
7222 return resolve_llvm_types_struct(g, type, wanted_resolve_status);
7860 return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr);
72237861 case ZigTypeIdEnum:
72247862 return resolve_llvm_types_enum(g, type);
72257863 case ZigTypeIdUnion:
72267864 return resolve_llvm_types_union(g, type, wanted_resolve_status);
72277865 case ZigTypeIdPointer:
7228 return resolve_llvm_types_pointer(g, type);
7229 case ZigTypeIdPromise: {
7230 if (type->llvm_di_type != nullptr) return;
7231 ZigType *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
7232 type->llvm_type = get_llvm_type(g, u8_ptr_type);
7233 type->llvm_di_type = get_llvm_di_type(g, u8_ptr_type);
7234 return;
7235 }
7866 return resolve_llvm_types_pointer(g, type, wanted_resolve_status);
72367867 case ZigTypeIdInt:
72377868 return resolve_llvm_types_integer(g, type);
72387869 case ZigTypeIdOptional:
......@@ -7242,7 +7873,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72427873 case ZigTypeIdArray:
72437874 return resolve_llvm_types_array(g, type);
72447875 case ZigTypeIdFn:
7245 return resolve_llvm_types_fn(g, type);
7876 return resolve_llvm_types_fn_type(g, type);
72467877 case ZigTypeIdErrorSet: {
72477878 if (type->llvm_di_type != nullptr) return;
72487879
......@@ -7261,14 +7892,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72617892 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);
72627893 return;
72637894 }
7895 case ZigTypeIdFnFrame:
7896 return resolve_llvm_types_async_frame(g, type, wanted_resolve_status);
7897 case ZigTypeIdAnyFrame:
7898 return resolve_llvm_types_any_frame(g, type, wanted_resolve_status);
72647899 }
72657900 zig_unreachable();
72667901}
72677902
72687903LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {
72697904 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));
7270 assert(type->abi_size == 0 || type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
7271 assert(type->abi_align == 0 || type->abi_align == LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
7905 assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
7906 assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
72727907 return type->llvm_type;
72737908}
72747909
src/analyze.hpp+8-10
......@@ -11,11 +11,12 @@
1111#include "all_types.hpp"
1212
1313void semantic_analyze(CodeGen *g);
14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
14ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg);
1515ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg);
1717void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
1818ZigType *new_type_table_entry(ZigTypeId id);
19ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
1920ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
2021ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
2122 bool is_volatile, PtrLen ptr_len,
......@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
3738ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
3839ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
3940ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
40ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
41 ZigType *field_types[], size_t field_count);
42ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
43ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type);
4441ZigType *get_test_fn_type(CodeGen *g);
42ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
4543bool handle_is_ptr(ZigType *type_entry);
4644
4745bool type_has_bits(ZigType *type_entry);
......@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
106104void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);
107105
108106void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
109void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node);
110107
111108ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
112109ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
......@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
117114ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
118115ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
119116Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
120Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
121117Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
122118
123119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
......@@ -199,12 +195,11 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global
199195
200196
201197ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
202ZigType *get_ptr_to_stack_trace_type(CodeGen *g);
198ZigType *get_stack_trace_type(CodeGen *g);
203199bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);
204200
205201ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);
206202
207uint32_t get_coro_frame_align_bytes(CodeGen *g);
208203bool fn_type_can_fail(FnTypeId *fn_type_id);
209204bool type_can_fail(ZigType *type_entry);
210205bool fn_eval_cacheable(Scope *scope, ZigType *return_type);
......@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);
251246bool is_container(ZigType *type_entry);
252247ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);
253248
249void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
250bool fn_is_async(ZigFn *fn);
251
254252#endif
src/ast_render.cpp+19-26
......@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {
249249 return "IfOptional";
250250 case NodeTypeErrorSetDecl:
251251 return "ErrorSetDecl";
252 case NodeTypeCancel:
253 return "Cancel";
254252 case NodeTypeResume:
255253 return "Resume";
256254 case NodeTypeAwaitExpr:
257255 return "AwaitExpr";
258256 case NodeTypeSuspend:
259257 return "Suspend";
260 case NodeTypePromiseType:
261 return "PromiseType";
262258 case NodeTypePointerType:
263259 return "PointerType";
260 case NodeTypeAnyFrameType:
261 return "AnyFrameType";
264262 case NodeTypeEnumLiteral:
265263 return "EnumLiteral";
266264 }
......@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
699697 fprintf(ar->f, "@");
700698 }
701699 if (node->data.fn_call_expr.is_async) {
702 fprintf(ar->f, "async");
703 if (node->data.fn_call_expr.async_allocator != nullptr) {
704 fprintf(ar->f, "<");
705 render_node_extra(ar, node->data.fn_call_expr.async_allocator, true);
706 fprintf(ar->f, ">");
707 }
708 fprintf(ar->f, " ");
700 fprintf(ar->f, "async ");
709701 }
710702 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
711703 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);
......@@ -862,15 +854,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
862854 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);
863855 break;
864856 }
865 case NodeTypePromiseType:
866 {
867 fprintf(ar->f, "promise");
868 if (node->data.promise_type.payload_type != nullptr) {
869 fprintf(ar->f, "->");
870 render_node_grouped(ar, node->data.promise_type.payload_type);
871 }
872 break;
857 case NodeTypeAnyFrameType: {
858 fprintf(ar->f, "anyframe");
859 if (node->data.anyframe_type.payload_type != nullptr) {
860 fprintf(ar->f, "->");
861 render_node_grouped(ar, node->data.anyframe_type.payload_type);
873862 }
863 break;
864 }
874865 case NodeTypeErrorType:
875866 fprintf(ar->f, "anyerror");
876867 break;
......@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
11431134 fprintf(ar->f, "}");
11441135 break;
11451136 }
1146 case NodeTypeCancel:
1147 {
1148 fprintf(ar->f, "cancel ");
1149 render_node_grouped(ar, node->data.cancel_expr.expr);
1150 break;
1151 }
11521137 case NodeTypeResume:
11531138 {
11541139 fprintf(ar->f, "resume ");
......@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
11631148 }
11641149 case NodeTypeSuspend:
11651150 {
1166 fprintf(ar->f, "suspend");
11671151 if (node->data.suspend.block != nullptr) {
1152 fprintf(ar->f, "suspend ");
11681153 render_node_grouped(ar, node->data.suspend.block);
1154 } else {
1155 fprintf(ar->f, "suspend\n");
11691156 }
11701157 break;
11711158 }
......@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {
11911178
11921179 render_node_grouped(&ar, node);
11931180}
1181
1182void AstNode::src() {
1183 fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize "\n",
1184 buf_ptr(this->owner->data.structure.root_struct->path),
1185 this->line + 1, this->column + 1);
1186}
src/codegen.cpp+1232-920
......@@ -24,6 +24,12 @@
2424#include <stdio.h>
2525#include <errno.h>
2626
27enum ResumeId {
28 ResumeIdManual,
29 ResumeIdReturn,
30 ResumeIdCall,
31};
32
2733static void init_darwin_native(CodeGen *g) {
2834 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
2935 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
......@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
297303 zig_unreachable();
298304}
299305
306// label (grep this): [fn_frame_struct_layout]
307static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) {
308 // [0] *ReturnType (callee's)
309 // [1] *ReturnType (awaiter's)
310 // [2] ReturnType
311 uint32_t return_field_count = type_has_bits(return_type) ? 3 : 0;
312 return frame_ret_start + return_field_count;
313}
314
315// label (grep this): [fn_frame_struct_layout]
316static uint32_t frame_index_arg(CodeGen *g, ZigType *return_type) {
317 bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, return_type);
318 // [0] *StackTrace (callee's)
319 // [1] *StackTrace (awaiter's)
320 uint32_t trace_field_count = have_stack_trace ? 2 : 0;
321 return frame_index_trace_arg(g, return_type) + trace_field_count;
322}
323
324// label (grep this): [fn_frame_struct_layout]
325static uint32_t frame_index_trace_stack(CodeGen *g, FnTypeId *fn_type_id) {
326 uint32_t result = frame_index_arg(g, fn_type_id->return_type);
327 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
328 if (type_has_bits(fn_type_id->param_info->type)) {
329 result += 1;
330 }
331 }
332 return result;
333}
334
335
300336static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
301337 if (!g->have_err_ret_tracing) {
302338 return UINT32_MAX;
303339 }
304 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
305 return 0;
340 if (fn_is_async(fn_table_entry)) {
341 return UINT32_MAX;
306342 }
307343 ZigType *fn_type = fn_table_entry->type_entry;
308344 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
......@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {
343379 zig_unreachable();
344380}
345381
346static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
347 if (fn_table_entry->llvm_value)
348 return fn_table_entry->llvm_value;
382static bool codegen_have_frame_pointer(CodeGen *g) {
383 return g->build_mode == BuildModeDebug;
384}
349385
350 Buf *unmangled_name = &fn_table_entry->symbol_name;
386static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
387 Buf *unmangled_name = &fn->symbol_name;
351388 Buf *symbol_name;
352389 GlobalLinkageId linkage;
353 if (fn_table_entry->body_node == nullptr) {
390 if (fn->body_node == nullptr) {
354391 symbol_name = unmangled_name;
355392 linkage = GlobalLinkageIdStrong;
356 } else if (fn_table_entry->export_list.length == 0) {
393 } else if (fn->export_list.length == 0) {
357394 symbol_name = get_mangled_name(g, unmangled_name, false);
358395 linkage = GlobalLinkageIdInternal;
359396 } else {
360 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
397 GlobalExport *fn_export = &fn->export_list.items[0];
361398 symbol_name = &fn_export->name;
362399 linkage = fn_export->linkage;
363400 }
364401
365402 bool external_linkage = linkage != GlobalLinkageIdInternal;
366 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
403 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
367404 if (cc == CallingConventionStdcall && external_linkage &&
368405 g->zig_target->arch == ZigLLVM_x86)
369406 {
......@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371408 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372409 }
373410
411 bool is_async = fn_is_async(fn);
374412
375 ZigType *fn_type = fn_table_entry->type_entry;
413
414 ZigType *fn_type = fn->type_entry;
376415 // Make the raw_type_ref populated
377 (void)get_llvm_type(g, fn_type);
378 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
379 if (fn_table_entry->body_node == nullptr) {
416 resolve_llvm_types_fn(g, fn);
417 LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
418 LLVMValueRef llvm_fn = nullptr;
419 if (fn->body_node == nullptr) {
380420 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
381421 if (existing_llvm_fn) {
382 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
383 return fn_table_entry->llvm_value;
422 return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
384423 } else {
385424 auto entry = g->exported_symbol_names.maybe_get(symbol_name);
386425 if (entry == nullptr) {
387 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
426 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
388427
389428 if (target_is_wasm(g->zig_target)) {
390 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
391 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
429 assert(fn->proto_node->type == NodeTypeFnProto);
430 AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
392431 if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {
393 addLLVMFnAttrStr(fn_table_entry->llvm_value, "wasm-import-module", buf_ptr(fn_proto->lib_name));
432 addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name));
394433 }
395434 }
396435 } else {
397436 assert(entry->value->id == TldIdFn);
398437 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
399438 // Make the raw_type_ref populated
400 (void)get_llvm_type(g, tld_fn->fn_entry->type_entry);
439 resolve_llvm_types_fn(g, tld_fn->fn_entry);
401440 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
402 tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);
403 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
404 LLVMPointerType(fn_llvm_type, 0));
405 return fn_table_entry->llvm_value;
441 tld_fn->fn_entry->raw_type_ref);
442 llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0));
443 return llvm_fn;
406444 }
407445 }
408446 } else {
409 if (fn_table_entry->llvm_value == nullptr) {
410 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
447 if (llvm_fn == nullptr) {
448 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
411449 }
412450
413 for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {
414 GlobalExport *fn_export = &fn_table_entry->export_list.items[i];
415 LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value),
416 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
451 for (size_t i = 1; i < fn->export_list.length; i += 1) {
452 GlobalExport *fn_export = &fn->export_list.items[i];
453 LLVMAddAlias(g->module, LLVMTypeOf(llvm_fn), llvm_fn, buf_ptr(&fn_export->name));
417454 }
418455 }
419 fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
420456
421 switch (fn_table_entry->fn_inline) {
457 switch (fn->fn_inline) {
422458 case FnInlineAlways:
423 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
424 g->inline_fns.append(fn_table_entry);
459 addLLVMFnAttr(llvm_fn, "alwaysinline");
460 g->inline_fns.append(fn);
425461 break;
426462 case FnInlineNever:
427 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
463 addLLVMFnAttr(llvm_fn, "noinline");
428464 break;
429465 case FnInlineAuto:
430 if (fn_table_entry->alignstack_value != 0) {
431 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
466 if (fn->alignstack_value != 0) {
467 addLLVMFnAttr(llvm_fn, "noinline");
432468 }
433469 break;
434470 }
435471
436472 if (cc == CallingConventionNaked) {
437 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
473 addLLVMFnAttr(llvm_fn, "naked");
438474 } else {
439 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
440 }
441 if (cc == CallingConventionAsync) {
442 addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
443 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
475 LLVMSetFunctionCallConv(llvm_fn, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
444476 }
445477
446 bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;
478 bool want_cold = fn->is_cold || cc == CallingConventionCold;
447479 if (want_cold) {
448 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
480 ZigLLVMAddFunctionAttrCold(llvm_fn);
449481 }
450482
451483
452 LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage));
484 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
453485
454486 if (linkage == GlobalLinkageIdInternal) {
455 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
487 LLVMSetUnnamedAddr(llvm_fn, true);
456488 }
457489
458490 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
459491 if (return_type->id == ZigTypeIdUnreachable) {
460 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
492 addLLVMFnAttr(llvm_fn, "noreturn");
461493 }
462494
463 if (fn_table_entry->body_node != nullptr) {
464 maybe_export_dll(g, fn_table_entry->llvm_value, linkage);
495 if (fn->body_node != nullptr) {
496 maybe_export_dll(g, llvm_fn, linkage);
465497
466498 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
467499 g->build_mode != BuildModeSmallRelease &&
468 !fn_table_entry->def_scope->safety_off;
500 !fn->def_scope->safety_off;
469501 if (want_fn_safety) {
470502 if (g->libc_link_lib != nullptr) {
471 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
472 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
503 addLLVMFnAttr(llvm_fn, "sspstrong");
504 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
473505 }
474506 }
475 if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) {
476 addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack");
507 if (g->have_stack_probing && !fn->def_scope->safety_off) {
508 addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack");
477509 }
478510 } else {
479 maybe_import_dll(g, fn_table_entry->llvm_value, linkage);
511 maybe_import_dll(g, llvm_fn, linkage);
480512 }
481513
482 if (fn_table_entry->alignstack_value != 0) {
483 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value);
514 if (fn->alignstack_value != 0) {
515 addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value);
484516 }
485517
486 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
487 add_uwtable_attr(g, fn_table_entry->llvm_value);
488 addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");
489 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
490 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
491 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
518 addLLVMFnAttr(llvm_fn, "nounwind");
519 add_uwtable_attr(g, llvm_fn);
520 addLLVMFnAttr(llvm_fn, "nobuiltin");
521 if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) {
522 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim", "true");
523 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim-non-leaf", nullptr);
492524 }
493 if (fn_table_entry->section_name) {
494 LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
525 if (fn->section_name) {
526 LLVMSetSection(llvm_fn, buf_ptr(fn->section_name));
495527 }
496 if (fn_table_entry->align_bytes > 0) {
497 LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
528 if (fn->align_bytes > 0) {
529 LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes);
498530 } else {
499531 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
500532 // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
......@@ -502,36 +534,50 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
502534 // use the ABI alignment, which is fine.
503535 }
504536
505 unsigned init_gen_i = 0;
506 if (!type_has_bits(return_type)) {
507 // nothing to do
508 } else if (type_is_nonnull_ptr(return_type)) {
509 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
510 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
511 // Sret pointers must not be address 0
512 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
513 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
514 if (cc_want_sret_attr(cc)) {
515 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
537 if (is_async) {
538 addLLVMArgAttr(llvm_fn, 0, "nonnull");
539 } else {
540 unsigned init_gen_i = 0;
541 if (!type_has_bits(return_type)) {
542 // nothing to do
543 } else if (type_is_nonnull_ptr(return_type)) {
544 addLLVMAttr(llvm_fn, 0, "nonnull");
545 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
546 // Sret pointers must not be address 0
547 addLLVMArgAttr(llvm_fn, 0, "nonnull");
548 addLLVMArgAttr(llvm_fn, 0, "sret");
549 if (cc_want_sret_attr(cc)) {
550 addLLVMArgAttr(llvm_fn, 0, "noalias");
551 }
552 init_gen_i = 1;
516553 }
517 init_gen_i = 1;
518 }
519554
520 // set parameter attributes
521 FnWalk fn_walk = {};
522 fn_walk.id = FnWalkIdAttrs;
523 fn_walk.data.attrs.fn = fn_table_entry;
524 fn_walk.data.attrs.gen_i = init_gen_i;
525 walk_function_params(g, fn_type, &fn_walk);
555 // set parameter attributes
556 FnWalk fn_walk = {};
557 fn_walk.id = FnWalkIdAttrs;
558 fn_walk.data.attrs.fn = fn;
559 fn_walk.data.attrs.llvm_fn = llvm_fn;
560 fn_walk.data.attrs.gen_i = init_gen_i;
561 walk_function_params(g, fn_type, &fn_walk);
526562
527 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
528 if (err_ret_trace_arg_index != UINT32_MAX) {
529 // Error return trace memory is in the stack, which is impossible to be at address 0
530 // on any architecture.
531 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
563 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn);
564 if (err_ret_trace_arg_index != UINT32_MAX) {
565 // Error return trace memory is in the stack, which is impossible to be at address 0
566 // on any architecture.
567 addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull");
568 }
532569 }
533570
534 return fn_table_entry->llvm_value;
571 return llvm_fn;
572}
573
574static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) {
575 if (fn->llvm_value)
576 return fn->llvm_value;
577
578 fn->llvm_value = make_fn_llvm_value(g, fn);
579 fn->llvm_name = strdup(LLVMGetValueName(fn->llvm_value));
580 return fn->llvm_value;
535581}
536582
537583static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
......@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
559605 unsigned flags = ZigLLVM_DIFlags_StaticMember;
560606 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);
561607 assert(fn_di_scope != nullptr);
608 assert(fn_table_entry->raw_di_type != nullptr);
562609 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
563610 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
564611 import->data.structure.root_struct->di_file, line_number,
565 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
612 fn_table_entry->raw_di_type, is_internal_linkage,
566613 is_definition, scope_line, flags, is_optimized, nullptr);
567614
568615 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
......@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
597644 case ScopeIdLoop:
598645 case ScopeIdSuspend:
599646 case ScopeIdCompTime:
600 case ScopeIdCoroPrelude:
601647 case ScopeIdRuntime:
602648 return get_di_scope(g, scope->parent);
603649 }
......@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
798844 return false;
799845}
800846
801static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
847static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) {
802848 // TODO memoize
803 Scope *scope = instruction->scope;
804849 while (scope) {
805850 if (scope->id == ScopeIdBlock) {
806851 ScopeBlock *block_scope = (ScopeBlock *)scope;
......@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
818863 g->build_mode != BuildModeSmallRelease);
819864}
820865
866static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
867 return ir_want_runtime_safety_scope(g, instruction->scope);
868}
869
821870static Buf *panic_msg_buf(PanicMsgId msg_id) {
822871 switch (msg_id) {
823872 case PanicMsgIdCount:
......@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
858907 return buf_create_from_str("integer part of floating point value out of bounds");
859908 case PanicMsgIdPtrCastNull:
860909 return buf_create_from_str("cast causes pointer to be null");
910 case PanicMsgIdBadResume:
911 return buf_create_from_str("resumed an async function which already returned");
912 case PanicMsgIdBadAwait:
913 return buf_create_from_str("async function awaited twice");
914 case PanicMsgIdBadReturn:
915 return buf_create_from_str("async function returned twice");
916 case PanicMsgIdResumedAnAwaitingFn:
917 return buf_create_from_str("awaiting function resumed");
918 case PanicMsgIdFrameTooSmall:
919 return buf_create_from_str("frame too small");
920 case PanicMsgIdResumedFnPendingAwait:
921 return buf_create_from_str("resumed an async function which can only be awaited");
861922 }
862923 zig_unreachable();
863924}
......@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
882943 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));
883944}
884945
946static ZigType *ptr_to_stack_trace_type(CodeGen *g) {
947 return get_pointer_to_type(g, get_stack_trace_type(g), false);
948}
949
885950static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
886951 assert(g->panic_fn != nullptr);
887952 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
888953 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
889954 if (stack_trace_arg == nullptr) {
890 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
891 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
955 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
892956 }
893957 LLVMValueRef args[] = {
894958 msg_arg,
......@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
904968 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
905969}
906970
907static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
908 if (ir_want_runtime_safety(g, source_instruction)) {
971static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) {
972 if (ir_want_runtime_safety_scope(g, source_scope)) {
909973 gen_safety_crash(g, msg_id);
910974 } else {
911975 LLVMBuildUnreachable(g->builder);
912976 }
913977}
914978
979static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
980 return gen_assertion_scope(g, msg_id, source_instruction->scope);
981}
982
915983static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
916984 if (g->stacksave_fn_val)
917985 return g->stacksave_fn_val;
......@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
9591027 return g->write_register_fn_val;
9601028}
9611029
962static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
963 if (g->coro_destroy_fn_val)
964 return g->coro_destroy_fn_val;
965
966 LLVMTypeRef param_types[] = {
967 LLVMPointerType(LLVMInt8Type(), 0),
968 };
969 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
970 Buf *name = buf_sprintf("llvm.coro.destroy");
971 g->coro_destroy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
972 assert(LLVMGetIntrinsicID(g->coro_destroy_fn_val));
973
974 return g->coro_destroy_fn_val;
975}
976
977static LLVMValueRef get_coro_id_fn_val(CodeGen *g) {
978 if (g->coro_id_fn_val)
979 return g->coro_id_fn_val;
980
981 LLVMTypeRef param_types[] = {
982 LLVMInt32Type(),
983 LLVMPointerType(LLVMInt8Type(), 0),
984 LLVMPointerType(LLVMInt8Type(), 0),
985 LLVMPointerType(LLVMInt8Type(), 0),
986 };
987 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 4, false);
988 Buf *name = buf_sprintf("llvm.coro.id");
989 g->coro_id_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
990 assert(LLVMGetIntrinsicID(g->coro_id_fn_val));
991
992 return g->coro_id_fn_val;
993}
994
995static LLVMValueRef get_coro_alloc_fn_val(CodeGen *g) {
996 if (g->coro_alloc_fn_val)
997 return g->coro_alloc_fn_val;
998
999 LLVMTypeRef param_types[] = {
1000 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1001 };
1002 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 1, false);
1003 Buf *name = buf_sprintf("llvm.coro.alloc");
1004 g->coro_alloc_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1005 assert(LLVMGetIntrinsicID(g->coro_alloc_fn_val));
1006
1007 return g->coro_alloc_fn_val;
1008}
1009
1010static LLVMValueRef get_coro_size_fn_val(CodeGen *g) {
1011 if (g->coro_size_fn_val)
1012 return g->coro_size_fn_val;
1013
1014 LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->llvm_type, nullptr, 0, false);
1015 Buf *name = buf_sprintf("llvm.coro.size.i%d", g->pointer_size_bytes * 8);
1016 g->coro_size_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1017 assert(LLVMGetIntrinsicID(g->coro_size_fn_val));
1018
1019 return g->coro_size_fn_val;
1020}
1021
1022static LLVMValueRef get_coro_begin_fn_val(CodeGen *g) {
1023 if (g->coro_begin_fn_val)
1024 return g->coro_begin_fn_val;
1025
1026 LLVMTypeRef param_types[] = {
1027 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1028 LLVMPointerType(LLVMInt8Type(), 0),
1029 };
1030 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1031 Buf *name = buf_sprintf("llvm.coro.begin");
1032 g->coro_begin_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1033 assert(LLVMGetIntrinsicID(g->coro_begin_fn_val));
1034
1035 return g->coro_begin_fn_val;
1036}
1037
1038static LLVMValueRef get_coro_suspend_fn_val(CodeGen *g) {
1039 if (g->coro_suspend_fn_val)
1040 return g->coro_suspend_fn_val;
1041
1042 LLVMTypeRef param_types[] = {
1043 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1044 LLVMInt1Type(),
1045 };
1046 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt8Type(), param_types, 2, false);
1047 Buf *name = buf_sprintf("llvm.coro.suspend");
1048 g->coro_suspend_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1049 assert(LLVMGetIntrinsicID(g->coro_suspend_fn_val));
1050
1051 return g->coro_suspend_fn_val;
1052}
1053
1054static LLVMValueRef get_coro_end_fn_val(CodeGen *g) {
1055 if (g->coro_end_fn_val)
1056 return g->coro_end_fn_val;
1057
1058 LLVMTypeRef param_types[] = {
1059 LLVMPointerType(LLVMInt8Type(), 0),
1060 LLVMInt1Type(),
1061 };
1062 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 2, false);
1063 Buf *name = buf_sprintf("llvm.coro.end");
1064 g->coro_end_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1065 assert(LLVMGetIntrinsicID(g->coro_end_fn_val));
1066
1067 return g->coro_end_fn_val;
1068}
1069
1070static LLVMValueRef get_coro_free_fn_val(CodeGen *g) {
1071 if (g->coro_free_fn_val)
1072 return g->coro_free_fn_val;
1073
1074 LLVMTypeRef param_types[] = {
1075 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1076 LLVMPointerType(LLVMInt8Type(), 0),
1077 };
1078 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1079 Buf *name = buf_sprintf("llvm.coro.free");
1080 g->coro_free_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1081 assert(LLVMGetIntrinsicID(g->coro_free_fn_val));
1082
1083 return g->coro_free_fn_val;
1084}
1085
1086static LLVMValueRef get_coro_resume_fn_val(CodeGen *g) {
1087 if (g->coro_resume_fn_val)
1088 return g->coro_resume_fn_val;
1089
1090 LLVMTypeRef param_types[] = {
1091 LLVMPointerType(LLVMInt8Type(), 0),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
1094 Buf *name = buf_sprintf("llvm.coro.resume");
1095 g->coro_resume_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_resume_fn_val));
1097
1098 return g->coro_resume_fn_val;
1099}
1100
1101static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
1102 if (g->coro_save_fn_val)
1103 return g->coro_save_fn_val;
1104
1105 LLVMTypeRef param_types[] = {
1106 LLVMPointerType(LLVMInt8Type(), 0),
1107 };
1108 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 1, false);
1109 Buf *name = buf_sprintf("llvm.coro.save");
1110 g->coro_save_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1111 assert(LLVMGetIntrinsicID(g->coro_save_fn_val));
1112
1113 return g->coro_save_fn_val;
1114}
1115
1116static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1117 if (g->coro_promise_fn_val)
1118 return g->coro_promise_fn_val;
1119
1120 LLVMTypeRef param_types[] = {
1121 LLVMPointerType(LLVMInt8Type(), 0),
1122 LLVMInt32Type(),
1123 LLVMInt1Type(),
1124 };
1125 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1126 Buf *name = buf_sprintf("llvm.coro.promise");
1127 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1128 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1129
1130 return g->coro_promise_fn_val;
1131}
1132
11331030static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
11341031 if (g->return_address_fn_val)
11351032 return g->return_address_fn_val;
......@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
11491046 return g->add_error_return_trace_addr_fn_val;
11501047
11511048 LLVMTypeRef arg_types[] = {
1152 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1049 get_llvm_type(g, ptr_to_stack_trace_type(g)),
11531050 g->builtin_types.entry_usize->llvm_type,
11541051 };
11551052 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
......@@ -1164,7 +1061,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
11641061 // Error return trace memory is in the stack, which is impossible to be at address 0
11651062 // on any architecture.
11661063 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1167 if (g->build_mode == BuildModeDebug) {
1064 if (codegen_have_frame_pointer(g)) {
11681065 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
11691066 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
11701067 }
......@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12221119 return fn_val;
12231120}
12241121
1225static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1226 if (g->merge_err_ret_traces_fn_val)
1227 return g->merge_err_ret_traces_fn_val;
1228
1229 assert(g->stack_trace_type != nullptr);
1230
1231 LLVMTypeRef param_types[] = {
1232 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1233 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1234 };
1235 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1236
1237 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1238 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1239 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1240 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1241 addLLVMFnAttr(fn_val, "nounwind");
1242 add_uwtable_attr(g, fn_val);
1243 // Error return trace memory is in the stack, which is impossible to be at address 0
1244 // on any architecture.
1245 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1246 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1247 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1248 // Error return trace memory is in the stack, which is impossible to be at address 0
1249 // on any architecture.
1250 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1251 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1252 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1253 if (g->build_mode == BuildModeDebug) {
1254 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1255 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1256 }
1257
1258 // this is above the ZigLLVMClearCurrentDebugLocation
1259 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1260
1261 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1262 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1263 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1264 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1265 ZigLLVMClearCurrentDebugLocation(g->builder);
1266
1267 // var frame_index: usize = undefined;
1268 // var frames_left: usize = undefined;
1269 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1270 // frame_index = 0;
1271 // frames_left = src_stack_trace.index;
1272 // if (frames_left == 0) return;
1273 // } else {
1274 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1275 // frames_left = src_stack_trace.instruction_addresses.len;
1276 // }
1277 // while (true) {
1278 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1279 // frames_left -= 1;
1280 // if (frames_left == 0) return;
1281 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1282 // }
1283 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1284
1285 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
1286 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
1287
1288 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1289 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1290
1291 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1292 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1293 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1294 (unsigned)src_index_field_index, "");
1295 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1296 (unsigned)src_addresses_field_index, "");
1297 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1298 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1299 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1300 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1301 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1302 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1303 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1304 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1305 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1306 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1307 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1308 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1309 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1310
1311 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1312 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
1313 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1314 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1315 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1316 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1317
1318 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1319 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
1320 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1321 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1322 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1323 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1324 LLVMBuildBr(g->builder, loop_block);
1325
1326 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1327 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1328 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1329 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1330 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1331 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1332 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1333 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1334 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1335 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1336 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1337
1338 LLVMPositionBuilderAtEnd(g->builder, return_block);
1339 LLVMBuildRetVoid(g->builder);
1340
1341 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1342 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1343 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1344 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1345 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1346 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1347 LLVMBuildBr(g->builder, loop_block);
1348
1349 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1350 if (!g->strip_debug_symbols) {
1351 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1352 }
1353
1354 g->merge_err_ret_traces_fn_val = fn_val;
1355 return fn_val;
1356
1357}
1358
13591122static LLVMValueRef get_return_err_fn(CodeGen *g) {
13601123 if (g->return_err_fn != nullptr)
13611124 return g->return_err_fn;
......@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13641127
13651128 LLVMTypeRef arg_types[] = {
13661129 // error return trace pointer
1367 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1130 get_llvm_type(g, ptr_to_stack_trace_type(g)),
13681131 };
13691132 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
13701133
......@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13761139 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
13771140 addLLVMFnAttr(fn_val, "nounwind");
13781141 add_uwtable_attr(g, fn_val);
1379 // Error return trace memory is in the stack, which is impossible to be at address 0
1380 // on any architecture.
1381 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1382 if (g->build_mode == BuildModeDebug) {
1142 if (codegen_have_frame_pointer(g)) {
13831143 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
13841144 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
13851145 }
......@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
14001160 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
14011161 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
14021162
1163 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1164 LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull");
1165
1166 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_ret_trace_ptr,
1167 LLVMConstNull(LLVMTypeOf(err_ret_trace_ptr)), "");
1168 LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block);
1169
1170 LLVMPositionBuilderAtEnd(g->builder, return_block);
1171 LLVMBuildRetVoid(g->builder);
1172
1173 LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block);
14031174 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
14041175 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
14051176 LLVMBuildRetVoid(g->builder);
......@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
14341205 LLVMTypeRef fn_type_ref;
14351206 if (g->have_err_ret_tracing) {
14361207 LLVMTypeRef arg_types[] = {
1437 get_llvm_type(g, g->ptr_to_stack_trace_type),
1208 get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)),
14381209 get_llvm_type(g, g->err_tag_type),
14391210 };
14401211 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
......@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
14511222 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
14521223 addLLVMFnAttr(fn_val, "nounwind");
14531224 add_uwtable_attr(g, fn_val);
1454 if (g->build_mode == BuildModeDebug) {
1225 if (codegen_have_frame_pointer(g)) {
14551226 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
14561227 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
14571228 }
......@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
15431314 return fn_val;
15441315}
15451316
1546static bool is_coro_prelude_scope(Scope *scope) {
1547 while (scope != nullptr) {
1548 if (scope->id == ScopeIdCoroPrelude) {
1549 return true;
1550 } else if (scope->id == ScopeIdFnDef) {
1551 break;
1552 }
1553 scope = scope->parent;
1554 }
1555 return false;
1556}
1557
15581317static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
15591318 if (!g->have_err_ret_tracing) {
15601319 return nullptr;
15611320 }
1562 if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
1563 return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack;
1564 }
15651321 if (g->cur_err_ret_trace_val_stack != nullptr) {
15661322 return g->cur_err_ret_trace_val_stack;
15671323 }
......@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
15741330 if (g->have_err_ret_tracing) {
15751331 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
15761332 if (err_ret_trace_val == nullptr) {
1577 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1578 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
1333 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
15791334 }
15801335 LLVMValueRef args[] = {
15811336 err_ret_trace_val,
......@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
18201575 }
18211576}
18221577
1823static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
1578static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
18241579 LLVMValueRef value)
18251580{
18261581 assert(ptr_type->id == ZigTypeIdPointer);
18271582 ZigType *child_type = ptr_type->data.pointer.child_type;
18281583
18291584 if (!type_has_bits(child_type))
1830 return nullptr;
1585 return;
18311586
18321587 if (handle_is_ptr(child_type)) {
18331588 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);
......@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18471602 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,
18481603 LLVMConstInt(usize->llvm_type, size_bytes, false),
18491604 ptr_type->data.pointer.is_volatile);
1850 return nullptr;
1605 return;
18511606 }
18521607
18531608 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
18541609 if (host_int_bytes == 0) {
18551610 gen_store(g, value, ptr, ptr_type);
1856 return nullptr;
1611 return;
18571612 }
18581613
18591614 bool big_endian = g->is_big_endian;
......@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18831638 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
18841639
18851640 gen_store(g, ored_value, ptr, ptr_type);
1886 return nullptr;
1641 return;
18871642}
18881643
18891644static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
......@@ -1967,7 +1722,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
19671722 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
19681723 ty = param_info->type;
19691724 source_node = fn_walk->data.attrs.fn->proto_node;
1970 llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1725 llvm_fn = fn_walk->data.attrs.llvm_fn;
19711726 break;
19721727 case FnWalkIdCall: {
19731728 if (src_i >= fn_walk->data.call.inst->arg_count)
......@@ -2149,10 +1904,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
21491904 }
21501905 case FnWalkIdInits: {
21511906 clear_debug_source_node(g);
2152 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2153 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2154 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2155 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1907 if (!fn_is_async(fn_walk->data.inits.fn)) {
1908 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
1909 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
1910 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
1911 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1912 }
21561913 if (var->decl_node) {
21571914 gen_var_debug_decl(g, var);
21581915 }
......@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22011958 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
22021959 assert(param_value);
22031960 fn_walk->data.call.gen_param_values->append(param_value);
1961 fn_walk->data.call.gen_param_types->append(param_type);
22041962 }
22051963 }
22061964 return;
......@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22161974
22171975 switch (fn_walk->id) {
22181976 case FnWalkIdAttrs: {
2219 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1977 LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn;
22201978 bool is_byval = gen_info->is_byval;
22211979 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
22221980
......@@ -2245,7 +2003,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22452003 assert(variable);
22462004 assert(variable->value_ref);
22472005
2248 if (!handle_is_ptr(variable->var_type)) {
2006 if (!handle_is_ptr(variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) {
22492007 clear_debug_source_node(g);
22502008 ZigType *fn_type = fn_table_entry->type_entry;
22512009 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;
......@@ -2271,48 +2029,357 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22712029 }
22722030}
22732031
2032static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
2033 if (g->merge_err_ret_traces_fn_val)
2034 return g->merge_err_ret_traces_fn_val;
2035
2036 assert(g->stack_trace_type != nullptr);
2037
2038 LLVMTypeRef param_types[] = {
2039 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2040 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2041 };
2042 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
2043
2044 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
2045 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
2046 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
2047 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
2048 addLLVMFnAttr(fn_val, "nounwind");
2049 add_uwtable_attr(g, fn_val);
2050 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
2051 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
2052
2053 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
2054 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
2055 if (g->build_mode == BuildModeDebug) {
2056 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
2057 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
2058 }
2059
2060 // this is above the ZigLLVMClearCurrentDebugLocation
2061 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
2062
2063 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
2064 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
2065 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
2066 LLVMPositionBuilderAtEnd(g->builder, entry_block);
2067 ZigLLVMClearCurrentDebugLocation(g->builder);
2068
2069 // if (dest_stack_trace == null or src_stack_trace == null) return;
2070 // var frame_index: usize = undefined;
2071 // var frames_left: usize = undefined;
2072 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
2073 // frame_index = 0;
2074 // frames_left = src_stack_trace.index;
2075 // if (frames_left == 0) return;
2076 // } else {
2077 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
2078 // frames_left = src_stack_trace.instruction_addresses.len;
2079 // }
2080 // while (true) {
2081 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
2082 // frames_left -= 1;
2083 // if (frames_left == 0) return;
2084 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
2085 // }
2086 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
2087 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull");
2088
2089 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
2090 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
2091
2092 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
2093 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
2094
2095 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr,
2096 LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), "");
2097 LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr,
2098 LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), "");
2099 LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, "");
2100 LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block);
2101
2102 LLVMPositionBuilderAtEnd(g->builder, non_null_block);
2103 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
2104 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
2105 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2106 (unsigned)src_index_field_index, "");
2107 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2108 (unsigned)src_addresses_field_index, "");
2109 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
2110 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
2111 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
2112 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
2113 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
2114 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
2115 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
2116 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
2117 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
2118 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
2119 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
2120 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
2121 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
2122
2123 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
2124 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
2125 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
2126 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
2127 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
2128 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
2129
2130 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
2131 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
2132 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
2133 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
2134 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
2135 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
2136 LLVMBuildBr(g->builder, loop_block);
2137
2138 LLVMPositionBuilderAtEnd(g->builder, loop_block);
2139 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2140 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
2141 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
2142 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
2143 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
2144 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
2145 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
2146 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
2147 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
2148 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
2149
2150 LLVMPositionBuilderAtEnd(g->builder, return_block);
2151 LLVMBuildRetVoid(g->builder);
2152
2153 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2154 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
2155 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2156 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
2157 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
2158 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
2159 LLVMBuildBr(g->builder, loop_block);
2160
2161 LLVMPositionBuilderAtEnd(g->builder, prev_block);
2162 if (!g->strip_debug_symbols) {
2163 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
2164 }
2165
2166 g->merge_err_ret_traces_fn_val = fn_val;
2167 return fn_val;
2168
2169}
22742170static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
22752171 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
22762172{
22772173 assert(g->have_err_ret_tracing);
22782174
22792175 LLVMValueRef return_err_fn = get_return_err_fn(g);
2280 LLVMValueRef args[] = {
2281 get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope),
2282 };
2283 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
2176 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2177 ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
22842178 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2285 return call_instruction;
2179
2180 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2181 if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
2182 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
2183 frame_index_trace_arg(g, ret_type), "");
2184 LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr);
2185 }
2186
2187 return nullptr;
2188}
2189
2190static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id,
2191 LLVMBasicBlockRef end_bb)
2192{
2193 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2194 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
2195 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
2196 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
2197 LLVMConstInt(usize_type_ref, resume_id, false));
2198 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, "");
2199 LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block);
2200
2201 LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
2202 gen_assertion(g, msg_id, source_instr);
2203
2204 LLVMPositionBuilderAtEnd(g->builder, end_bb);
22862205}
22872206
2288static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
2207static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef target_frame_ptr, ResumeId resume_id) {
2208 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2209 if (fn_val == nullptr) {
2210 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_fn_ptr_index, "");
2211 fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");
2212 }
2213 LLVMValueRef arg_val = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref),
2214 LLVMConstInt(usize_type_ref, resume_id, false), "");
2215 LLVMValueRef args[] = {target_frame_ptr, arg_val};
2216 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
2217}
2218
2219static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) {
2220 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2221 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint);
2222 size_t new_block_index = g->cur_resume_block_count;
2223 g->cur_resume_block_count += 1;
2224 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
2225 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb);
2226 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
2227 return resume_bb;
2228}
2229
2230static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) {
2231 LLVMSetTailCall(call_inst, true);
2232}
2233
2234static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMValueRef ptr, LLVMValueRef val,
2235 LLVMAtomicOrdering order)
2236{
2237 if (g->is_single_threaded) {
2238 LLVMValueRef loaded = LLVMBuildLoad(g->builder, ptr, "");
2239 LLVMValueRef modified;
2240 switch (op) {
2241 case LLVMAtomicRMWBinOpXchg:
2242 modified = val;
2243 break;
2244 case LLVMAtomicRMWBinOpXor:
2245 modified = LLVMBuildXor(g->builder, loaded, val, "");
2246 break;
2247 default:
2248 zig_unreachable();
2249 }
2250 LLVMBuildStore(g->builder, modified, ptr);
2251 return loaded;
2252 } else {
2253 return LLVMBuildAtomicRMW(g->builder, op, ptr, val, order, false);
2254 }
2255}
2256
2257static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) {
2258 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2259
2260 ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value.type : nullptr;
2261 bool operand_has_bits = (operand_type != nullptr) && type_has_bits(operand_type);
2262 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2263 bool ret_type_has_bits = type_has_bits(ret_type);
2264
2265 if (operand_has_bits && instruction->operand != nullptr) {
2266 bool need_store = instruction->operand->value.special != ConstValSpecialRuntime || !handle_is_ptr(ret_type);
2267 if (need_store) {
2268 // It didn't get written to the result ptr. We do that now.
2269 ZigType *ret_ptr_type = get_pointer_to_type(g, ret_type, true);
2270 gen_assign_raw(g, g->cur_ret_ptr, ret_ptr_type, ir_llvm_value(g, instruction->operand));
2271 }
2272 }
2273
2274 // Whether we tail resume the awaiter, or do an early return, we are done and will not be resumed.
2275 if (ir_want_runtime_safety(g, &instruction->base)) {
2276 LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref);
2277 LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr);
2278 }
2279
2280 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
2281 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
2282
2283 LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXor, g->cur_async_awaiter_ptr,
2284 all_ones, LLVMAtomicOrderingAcquire);
2285
2286 LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn");
2287 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
2288 LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem");
2289
2290 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2);
2291
2292 LLVMAddCase(switch_instr, zero, early_return_block);
2293 LLVMAddCase(switch_instr, all_ones, bad_return_block);
2294
2295 // Something has gone horribly wrong, and this is an invalid second return.
2296 LLVMPositionBuilderAtEnd(g->builder, bad_return_block);
2297 gen_assertion(g, PanicMsgIdBadReturn, &instruction->base);
2298
2299 // There is no awaiter yet, but we're completely done.
2300 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
2301 LLVMBuildRetVoid(g->builder);
2302
2303 // We need to resume the caller by tail calling them,
2304 // but first write through the result pointer and possibly
2305 // error return trace pointer.
2306 LLVMPositionBuilderAtEnd(g->builder, resume_them_block);
2307
2308 if (ret_type_has_bits) {
2309 // If the awaiter result pointer is non-null, we need to copy the result to there.
2310 LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult");
2311 LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd");
2312 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start + 1, "");
2313 LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad(g->builder, awaiter_ret_ptr_ptr, "");
2314 LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr));
2315 LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, "");
2316 LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block);
2317
2318 LLVMPositionBuilderAtEnd(g->builder, copy_block);
2319 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
2320 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, "");
2321 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, "");
2322 bool is_volatile = false;
2323 uint32_t abi_align = get_abi_alignment(g, ret_type);
2324 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false);
2325 ZigLLVMBuildMemCpy(g->builder,
2326 dest_ptr_casted, abi_align,
2327 src_ptr_casted, abi_align, byte_count_val, is_volatile);
2328 LLVMBuildBr(g->builder, copy_end_block);
2329
2330 LLVMPositionBuilderAtEnd(g->builder, copy_end_block);
2331 if (codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
2332 LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
2333 frame_index_trace_arg(g, ret_type) + 1, "");
2334 LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, awaiter_trace_ptr_ptr, "");
2335 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
2336 LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val };
2337 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
2338 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2339 }
2340 }
2341
2342 // Resume the caller by tail calling them.
2343 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
2344 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val, get_llvm_type(g, any_frame_type), "");
2345 LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn);
2346 set_tail_call_if_appropriate(g, call_inst);
2347 LLVMBuildRetVoid(g->builder);
2348}
2349
2350static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *instruction) {
2351 if (fn_is_async(g->cur_fn)) {
2352 gen_async_return(g, instruction);
2353 return nullptr;
2354 }
2355
22892356 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
2290 if (return_instruction->value == nullptr) {
2357 if (instruction->operand == nullptr) {
22912358 LLVMBuildRetVoid(g->builder);
22922359 return nullptr;
22932360 }
22942361 assert(g->cur_ret_ptr);
2295 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,
2296 return_instruction->base.source_node);
2297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2298 ZigType *return_type = return_instruction->value->value.type;
2362 src_assert(instruction->operand->value.special != ConstValSpecialRuntime,
2363 instruction->base.source_node);
2364 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2365 ZigType *return_type = instruction->operand->value.type;
22992366 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
23002367 LLVMBuildRetVoid(g->builder);
23012368 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
23022369 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
23032370 {
2304 if (return_instruction->value == nullptr) {
2371 if (instruction->operand == nullptr) {
23052372 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
23062373 LLVMBuildRet(g->builder, by_val_value);
23072374 } else {
2308 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2375 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
23092376 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
23102377 LLVMBuildRet(g->builder, by_val_value);
23112378 }
2312 } else if (return_instruction->value == nullptr) {
2379 } else if (instruction->operand == nullptr) {
23132380 LLVMBuildRetVoid(g->builder);
23142381 } else {
2315 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2382 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
23162383 LLVMBuildRet(g->builder, value);
23172384 }
23182385 return nullptr;
......@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
32423309 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
32433310}
32443311
3245static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
3246 ZigVar *var = instruction->var;
3247
3312static void render_decl_var(CodeGen *g, ZigVar *var) {
32483313 if (!type_has_bits(var->var_type))
3249 return nullptr;
3314 return;
32503315
3251 var->value_ref = ir_llvm_value(g, instruction->var_ptr);
3316 var->value_ref = ir_llvm_value(g, var->ptr_instruction);
32523317 gen_var_debug_decl(g, var);
3318}
3319
3320static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
3321 instruction->var->ptr_instruction = instruction->var_ptr;
3322 render_decl_var(g, instruction->var);
32533323 return nullptr;
32543324}
32553325
......@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
34673537static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,
34683538 IrInstructionReturnPtr *instruction)
34693539{
3470 src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type),
3471 instruction->base.source_node);
3540 if (!type_has_bits(instruction->base.value.type))
3541 return nullptr;
3542 src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node);
34723543 return g->cur_ret_ptr;
34733544}
34743545
......@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
35663637 }
35673638}
35683639
3569static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) {
3570 return g->have_err_ret_tracing &&
3571 (fn_type_id->return_type->id == ZigTypeIdErrorUnion ||
3572 fn_type_id->return_type->id == ZigTypeIdErrorSet ||
3573 fn_type_id->cc == CallingConventionAsync);
3574}
3575
3576static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3577 // 0 1 2 3
3578 // err_ret_stack allocator_ptr err_code other_args...
3579 return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0;
3580}
3581
3582static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3583 // 0 1 2 3
3584 // err_ret_stack allocator_ptr err_code other_args...
3585 return 1 + get_async_allocator_arg_index(g, fn_type_id);
3586}
3587
3588
35893640static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
35903641 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
35913642 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
......@@ -3623,16 +3674,124 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
36233674 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
36243675}
36253676
3677static void render_async_spills(CodeGen *g) {
3678 ZigType *fn_type = g->cur_fn->type_entry;
3679 ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base);
3680 uint32_t async_var_index = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3681 for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) {
3682 ZigVar *var = g->cur_fn->variable_list.at(var_i);
3683
3684 if (!type_has_bits(var->var_type)) {
3685 continue;
3686 }
3687 if (ir_get_var_is_comptime(var))
3688 continue;
3689 switch (type_requires_comptime(g, var->var_type)) {
3690 case ReqCompTimeInvalid:
3691 zig_unreachable();
3692 case ReqCompTimeYes:
3693 continue;
3694 case ReqCompTimeNo:
3695 break;
3696 }
3697 if (var->src_arg_index == SIZE_MAX) {
3698 continue;
3699 }
3700
3701 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index,
3702 buf_ptr(&var->name));
3703 async_var_index += 1;
3704 if (var->decl_node) {
3705 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
3706 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
3707 (unsigned)(var->decl_node->line + 1),
3708 get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
3709 gen_var_debug_decl(g, var);
3710 }
3711 }
3712
3713 ZigType *frame_type = g->cur_fn->frame_type->data.frame.locals_struct;
3714
3715 for (size_t alloca_i = 0; alloca_i < g->cur_fn->alloca_gen_list.length; alloca_i += 1) {
3716 IrInstructionAllocaGen *instruction = g->cur_fn->alloca_gen_list.at(alloca_i);
3717 if (instruction->field_index == SIZE_MAX)
3718 continue;
3719
3720 size_t gen_index = frame_type->data.structure.fields[instruction->field_index].gen_index;
3721 instruction->base.llvm_value = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, gen_index,
3722 instruction->name_hint);
3723 }
3724}
3725
3726static void render_async_var_decls(CodeGen *g, Scope *scope) {
3727 for (;;) {
3728 switch (scope->id) {
3729 case ScopeIdCImport:
3730 zig_unreachable();
3731 case ScopeIdFnDef:
3732 return;
3733 case ScopeIdVarDecl: {
3734 ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
3735 if (var->ptr_instruction != nullptr) {
3736 render_decl_var(g, var);
3737 }
3738 // fallthrough
3739 }
3740 case ScopeIdDecls:
3741 case ScopeIdBlock:
3742 case ScopeIdDefer:
3743 case ScopeIdDeferExpr:
3744 case ScopeIdLoop:
3745 case ScopeIdSuspend:
3746 case ScopeIdCompTime:
3747 case ScopeIdRuntime:
3748 scope = scope->parent;
3749 continue;
3750 }
3751 }
3752}
3753
3754static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
3755 LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
3756 LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
3757 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
3758 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
3759 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
3760 return LLVMBuildLoad(g->builder, prefix_ptr, "");
3761}
3762
3763static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
3764 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3765 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3766
3767 LLVMValueRef index_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 0, "");
3768 LLVMBuildStore(g->builder, zero, index_ptr);
3769
3770 LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 1, "");
3771 LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_ptr_index, "");
3772 LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) };
3773 LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP(g->builder, addrs_field_ptr, indices, 2, "");
3774 LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr);
3775
3776 LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_len_index, "");
3777 LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr);
3778}
3779
36263780static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3781 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3782
36273783 LLVMValueRef fn_val;
36283784 ZigType *fn_type;
3785 bool callee_is_async;
36293786 if (instruction->fn_entry) {
36303787 fn_val = fn_llvm_value(g, instruction->fn_entry);
36313788 fn_type = instruction->fn_entry->type_entry;
3789 callee_is_async = fn_is_async(instruction->fn_entry);
36323790 } else {
36333791 assert(instruction->fn_ref);
36343792 fn_val = ir_llvm_value(g, instruction->fn_ref);
36353793 fn_type = instruction->fn_ref->value.type;
3794 callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync;
36363795 }
36373796
36383797 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -3643,27 +3802,154 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36433802 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
36443803
36453804 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
3646 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
3805 bool prefix_arg_err_ret_stack = codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type);
36473806 bool is_var_args = fn_type_id->is_var_args;
36483807 ZigList<LLVMValueRef> gen_param_values = {};
3808 ZigList<ZigType *> gen_param_types = {};
36493809 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3650 if (first_arg_ret) {
3651 gen_param_values.append(result_loc);
3652 }
3653 if (prefix_arg_err_ret_stack) {
3654 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3655 }
3656 if (instruction->is_async) {
3657 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
3810 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3811 LLVMValueRef frame_result_loc;
3812 LLVMValueRef awaiter_init_val;
3813 LLVMValueRef ret_ptr;
3814 if (callee_is_async) {
3815 if (instruction->is_async) {
3816 if (instruction->new_stack == nullptr) {
3817 awaiter_init_val = zero;
3818 frame_result_loc = result_loc;
3819
3820 if (ret_has_bits) {
3821 // Use the result location which is inside the frame if this is an async call.
3822 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3823 }
3824 } else if (cc == CallingConventionAsync) {
3825 awaiter_init_val = zero;
3826 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3827 if (ir_want_runtime_safety(g, &instruction->base)) {
3828 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3829 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3830 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3831
3832 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3833 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3834
3835 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3836 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
3837
3838 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3839 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
36583840
3659 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, "");
3660 gen_param_values.append(err_val_ptr);
3841 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3842 }
3843 LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
3844 LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
3845 frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
3846 get_llvm_type(g, instruction->base.value.type), "");
3847
3848 if (ret_has_bits) {
3849 // Use the result location provided to the @asyncCall builtin
3850 ret_ptr = result_loc;
3851 }
3852 }
3853
3854 // even if prefix_arg_err_ret_stack is true, let the async function do its own
3855 // initialization.
3856 } else {
3857 // async function called as a normal function
3858
3859 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
3860 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer
3861 if (ret_has_bits) {
3862 if (result_loc == nullptr) {
3863 // return type is a scalar, but we still need a pointer to it. Use the async fn frame.
3864 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3865 } else {
3866 // Use the call instruction's result location.
3867 ret_ptr = result_loc;
3868 }
3869
3870 // Store a zero in the awaiter's result ptr to indicate we do not need a copy made.
3871 LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, "");
3872 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr)));
3873 LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr);
3874 }
3875
3876 if (prefix_arg_err_ret_stack) {
3877 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3878 frame_index_trace_arg(g, src_return_type) + 1, "");
3879 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3880 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
3881 }
3882 }
3883
3884 assert(frame_result_loc != nullptr);
3885
3886 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_fn_ptr_index, "");
3887 LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val,
3888 LLVMGetElementType(LLVMTypeOf(fn_ptr_ptr)), "");
3889 LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr);
3890
3891 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_resume_index, "");
3892 LLVMBuildStore(g->builder, zero, resume_index_ptr);
3893
3894 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_awaiter_index, "");
3895 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3896
3897 if (ret_has_bits) {
3898 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3899 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3900 }
3901 } else if (instruction->is_async) {
3902 // Async call of blocking function
3903 if (instruction->new_stack != nullptr) {
3904 zig_panic("TODO @asyncCall of non-async function");
3905 }
3906 frame_result_loc = result_loc;
3907 awaiter_init_val = LLVMConstAllOnes(usize_type_ref);
3908
3909 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_awaiter_index, "");
3910 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3911
3912 if (ret_has_bits) {
3913 LLVMValueRef ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3914 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3915 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3916
3917 if (first_arg_ret) {
3918 gen_param_values.append(ret_ptr);
3919 }
3920 if (prefix_arg_err_ret_stack) {
3921 // Set up the callee stack trace pointer pointing into the frame.
3922 // Then we have to wire up the StackTrace pointers.
3923 // Await is responsible for merging error return traces.
3924 uint32_t trace_field_index_start = frame_index_trace_arg(g, src_return_type);
3925 LLVMValueRef callee_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3926 trace_field_index_start, "");
3927 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3928 trace_field_index_start + 2, "");
3929 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3930 trace_field_index_start + 3, "");
3931
3932 LLVMBuildStore(g->builder, trace_field_ptr, callee_trace_ptr_ptr);
3933
3934 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
3935
3936 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3937 }
3938 }
3939 } else {
3940 if (first_arg_ret) {
3941 gen_param_values.append(result_loc);
3942 }
3943 if (prefix_arg_err_ret_stack) {
3944 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3945 }
36613946 }
36623947 FnWalk fn_walk = {};
36633948 fn_walk.id = FnWalkIdCall;
36643949 fn_walk.data.call.inst = instruction;
36653950 fn_walk.data.call.is_var_args = is_var_args;
36663951 fn_walk.data.call.gen_param_values = &gen_param_values;
3952 fn_walk.data.call.gen_param_types = &gen_param_types;
36673953 walk_function_params(g, fn_type, &fn_walk);
36683954
36693955 ZigLLVM_FnInline fn_inline;
......@@ -3679,12 +3965,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36793965 break;
36803966 }
36813967
3682 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3683 LLVMValueRef result;
3968 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3969 LLVMValueRef result;
3970
3971 if (callee_is_async) {
3972 uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3973
3974 LLVMValueRef casted_frame;
3975 if (instruction->new_stack != nullptr) {
3976 // We need the frame type to be a pointer to a struct that includes the args
3977 size_t field_count = arg_start_i + gen_param_values.length;
3978 LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count);
3979 LLVMGetStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc)), field_types);
3980 assert(LLVMCountStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc))) == arg_start_i);
3981 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3982 field_types[arg_start_i + arg_i] = LLVMTypeOf(gen_param_values.at(arg_i));
3983 }
3984 LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false);
3985 LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0);
3986
3987 casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, "");
3988 } else {
3989 casted_frame = frame_result_loc;
3990 }
3991
3992 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3993 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, casted_frame, arg_start_i + arg_i, "");
3994 gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true),
3995 gen_param_values.at(arg_i));
3996 }
3997
3998 if (instruction->is_async) {
3999 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
4000 if (instruction->new_stack != nullptr) {
4001 return frame_result_loc;
4002 }
4003 return nullptr;
4004 } else {
4005 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
4006
4007 LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume");
4008
4009 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
4010 set_tail_call_if_appropriate(g, call_inst);
4011 LLVMBuildRetVoid(g->builder);
4012
4013 LLVMPositionBuilderAtEnd(g->builder, call_bb);
4014 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
4015 render_async_var_decls(g, instruction->base.scope);
4016
4017 if (!type_has_bits(src_return_type))
4018 return nullptr;
4019
4020 if (result_loc != nullptr)
4021 return get_handle_value(g, result_loc, src_return_type, ptr_result_type);
4022
4023 LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
4024 return LLVMBuildLoad(g->builder, result_ptr, "");
4025 }
4026 }
36844027
36854028 if (instruction->new_stack == nullptr) {
36864029 result = ZigLLVMBuildCall(g->builder, fn_val,
36874030 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
4031 } else if (instruction->is_async) {
4032 zig_panic("TODO @asyncCall of non-async function");
36884033 } else {
36894034 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
36904035 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
......@@ -3697,13 +4042,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36974042 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
36984043 }
36994044
3700
3701 if (instruction->is_async) {
3702 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_payload_index, "");
3703 LLVMBuildStore(g->builder, result, payload_ptr);
3704 return result_loc;
3705 }
3706
37074045 if (src_return_type->id == ZigTypeIdUnreachable) {
37084046 return LLVMBuildUnreachable(g->builder);
37094047 } else if (!ret_has_bits) {
......@@ -4200,7 +4538,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
42004538 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
42014539 addLLVMFnAttr(fn_val, "nounwind");
42024540 add_uwtable_attr(g, fn_val);
4203 if (g->build_mode == BuildModeDebug) {
4541 if (codegen_have_frame_pointer(g)) {
42044542 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
42054543 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
42064544 }
......@@ -4347,10 +4685,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
43474685 {
43484686 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
43494687 ptr_val = target_val;
4350 } else if (target_type->id == ZigTypeIdOptional &&
4351 target_type->data.maybe.child_type->id == ZigTypeIdPromise)
4352 {
4353 zig_panic("TODO audit this function");
43544688 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
43554689 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
43564690 align_bytes = get_ptr_align(g, slice_ptr_type);
......@@ -4388,26 +4722,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
43884722{
43894723 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
43904724 if (cur_err_ret_trace_val == nullptr) {
4391 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
4392 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
4725 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
43934726 }
43944727 return cur_err_ret_trace_val;
43954728}
43964729
4397static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
4398 LLVMValueRef target_handle = ir_llvm_value(g, instruction->target);
4399 LLVMBuildCall(g->builder, get_coro_destroy_fn_val(g), &target_handle, 1, "");
4400 return nullptr;
4401}
4402
4403static LLVMValueRef ir_render_get_implicit_allocator(CodeGen *g, IrExecutable *executable,
4404 IrInstructionGetImplicitAllocator *instruction)
4405{
4406 assert(instruction->id == ImplicitAllocatorIdArg);
4407 size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
4408 return LLVMGetParam(g->cur_fn_val, allocator_arg_index);
4409}
4410
44114730static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
44124731 switch (atomic_order) {
44134732 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -4722,24 +5041,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
47225041 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
47235042}
47245043
4725static LLVMValueRef get_handle_fn_val(CodeGen *g) {
4726 if (g->coro_frame_fn_val)
4727 return g->coro_frame_fn_val;
4728
4729 LLVMTypeRef fn_type = LLVMFunctionType( LLVMPointerType(LLVMInt8Type(), 0)
4730 , nullptr, 0, false);
4731 Buf *name = buf_sprintf("llvm.coro.frame");
4732 g->coro_frame_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
4733 assert(LLVMGetIntrinsicID(g->coro_frame_fn_val));
4734
4735 return g->coro_frame_fn_val;
4736}
4737
4738static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
4739 IrInstructionHandle *instruction)
4740{
4741 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_promise));
4742 return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
5044static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable, IrInstructionFrameHandle *instruction) {
5045 return g->cur_frame_ptr;
47435046}
47445047
47455048static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
......@@ -5005,248 +5308,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
50055308 return nullptr;
50065309}
50075310
5008static LLVMValueRef ir_render_coro_id(CodeGen *g, IrExecutable *executable, IrInstructionCoroId *instruction) {
5009 LLVMValueRef promise_ptr = ir_llvm_value(g, instruction->promise_ptr);
5010 LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false);
5011 LLVMValueRef null = LLVMConstIntToPtr(LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
5012 LLVMPointerType(LLVMInt8Type(), 0));
5013 LLVMValueRef params[] = {
5014 align_val,
5015 promise_ptr,
5016 null,
5017 null,
5018 };
5019 return LLVMBuildCall(g->builder, get_coro_id_fn_val(g), params, 4, "");
5020}
5021
5022static LLVMValueRef ir_render_coro_alloc(CodeGen *g, IrExecutable *executable, IrInstructionCoroAlloc *instruction) {
5023 LLVMValueRef token = ir_llvm_value(g, instruction->coro_id);
5024 return LLVMBuildCall(g->builder, get_coro_alloc_fn_val(g), &token, 1, "");
5025}
5026
5027static LLVMValueRef ir_render_coro_size(CodeGen *g, IrExecutable *executable, IrInstructionCoroSize *instruction) {
5028 return LLVMBuildCall(g->builder, get_coro_size_fn_val(g), nullptr, 0, "");
5029}
5030
5031static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, IrInstructionCoroBegin *instruction) {
5032 LLVMValueRef coro_id = ir_llvm_value(g, instruction->coro_id);
5033 LLVMValueRef coro_mem_ptr = ir_llvm_value(g, instruction->coro_mem_ptr);
5034 LLVMValueRef params[] = {
5035 coro_id,
5036 coro_mem_ptr,
5037 };
5038 return LLVMBuildCall(g->builder, get_coro_begin_fn_val(g), params, 2, "");
5039}
5040
5041static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executable,
5042 IrInstructionCoroAllocFail *instruction)
5043{
5044 size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
5045 LLVMValueRef err_code_ptr_val = LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index);
5046 LLVMValueRef err_code = ir_llvm_value(g, instruction->err_val);
5047 LLVMBuildStore(g->builder, err_code, err_code_ptr_val);
5048
5049 LLVMValueRef return_value;
5050 if (ir_want_runtime_safety(g, &instruction->base)) {
5051 return_value = LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0));
5052 } else {
5053 return_value = LLVMGetUndef(LLVMPointerType(LLVMInt8Type(), 0));
5054 }
5055 LLVMBuildRet(g->builder, return_value);
5056 return nullptr;
5057}
5058
5059static LLVMValueRef ir_render_coro_suspend(CodeGen *g, IrExecutable *executable, IrInstructionCoroSuspend *instruction) {
5060 LLVMValueRef save_point;
5061 if (instruction->save_point == nullptr) {
5062 save_point = LLVMConstNull(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()));
5063 } else {
5064 save_point = ir_llvm_value(g, instruction->save_point);
5065 }
5066 LLVMValueRef is_final = ir_llvm_value(g, instruction->is_final);
5067 LLVMValueRef params[] = {
5068 save_point,
5069 is_final,
5070 };
5071 return LLVMBuildCall(g->builder, get_coro_suspend_fn_val(g), params, 2, "");
5072}
5073
5074static LLVMValueRef ir_render_coro_end(CodeGen *g, IrExecutable *executable, IrInstructionCoroEnd *instruction) {
5075 LLVMValueRef params[] = {
5076 LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)),
5077 LLVMConstNull(LLVMInt1Type()),
5078 };
5079 return LLVMBuildCall(g->builder, get_coro_end_fn_val(g), params, 2, "");
5080}
5081
5082static LLVMValueRef ir_render_coro_free(CodeGen *g, IrExecutable *executable, IrInstructionCoroFree *instruction) {
5083 LLVMValueRef coro_id = ir_llvm_value(g, instruction->coro_id);
5084 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
5085 LLVMValueRef params[] = {
5086 coro_id,
5087 coro_handle,
5088 };
5089 return LLVMBuildCall(g->builder, get_coro_free_fn_val(g), params, 2, "");
5090}
5091
5092static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, IrInstructionCoroResume *instruction) {
5093 LLVMValueRef awaiter_handle = ir_llvm_value(g, instruction->awaiter_handle);
5094 return LLVMBuildCall(g->builder, get_coro_resume_fn_val(g), &awaiter_handle, 1, "");
5095}
5096
5097static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, IrInstructionCoroSave *instruction) {
5098 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
5099 return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");
5100}
5101
5102static LLVMValueRef ir_render_coro_promise(CodeGen *g, IrExecutable *executable, IrInstructionCoroPromise *instruction) {
5103 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
5104 LLVMValueRef params[] = {
5105 coro_handle,
5106 LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false),
5107 LLVMConstNull(LLVMInt1Type()),
5108 };
5109 LLVMValueRef uncasted_result = LLVMBuildCall(g->builder, get_coro_promise_fn_val(g), params, 3, "");
5110 return LLVMBuildBitCast(g->builder, uncasted_result, get_llvm_type(g, instruction->base.value.type), "");
5111}
5112
5113static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, ZigType *fn_type) {
5114 if (g->coro_alloc_helper_fn_val != nullptr)
5115 return g->coro_alloc_helper_fn_val;
5116
5117 assert(fn_type->id == ZigTypeIdFn);
5118
5119 ZigType *ptr_to_err_code_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
5120
5121 LLVMTypeRef alloc_raw_fn_type_ref = LLVMGetElementType(alloc_fn_type_ref);
5122 LLVMTypeRef *alloc_fn_arg_types = allocate<LLVMTypeRef>(LLVMCountParamTypes(alloc_raw_fn_type_ref));
5123 LLVMGetParamTypes(alloc_raw_fn_type_ref, alloc_fn_arg_types);
5124
5125 ZigList<LLVMTypeRef> arg_types = {};
5126 arg_types.append(alloc_fn_type_ref);
5127 if (g->have_err_ret_tracing) {
5128 arg_types.append(alloc_fn_arg_types[1]);
5129 }
5130 arg_types.append(alloc_fn_arg_types[g->have_err_ret_tracing ? 2 : 1]);
5131 arg_types.append(get_llvm_type(g, ptr_to_err_code_type));
5132 arg_types.append(g->builtin_types.entry_usize->llvm_type);
5133
5134 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0),
5135 arg_types.items, arg_types.length, false);
5136
5137 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_coro_alloc_helper"), false);
5138 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
5139 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
5140 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
5141 addLLVMFnAttr(fn_val, "nounwind");
5142 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
5143 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
5144
5145 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
5146 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
5147 ZigFn *prev_cur_fn = g->cur_fn;
5148 LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
5149
5150 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
5151 LLVMPositionBuilderAtEnd(g->builder, entry_block);
5152 ZigLLVMClearCurrentDebugLocation(g->builder);
5153 g->cur_fn = nullptr;
5154 g->cur_fn_val = fn_val;
5155
5156 LLVMValueRef sret_ptr = LLVMBuildAlloca(g->builder, LLVMGetElementType(alloc_fn_arg_types[0]), "");
5157
5158 size_t next_arg = 0;
5159 LLVMValueRef realloc_fn_val = LLVMGetParam(fn_val, next_arg);
5160 next_arg += 1;
5161
5162 LLVMValueRef stack_trace_val;
5163 if (g->have_err_ret_tracing) {
5164 stack_trace_val = LLVMGetParam(fn_val, next_arg);
5165 next_arg += 1;
5166 }
5167
5168 LLVMValueRef allocator_val = LLVMGetParam(fn_val, next_arg);
5169 next_arg += 1;
5170 LLVMValueRef err_code_ptr = LLVMGetParam(fn_val, next_arg);
5171 next_arg += 1;
5172 LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
5173 next_arg += 1;
5174 LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->llvm_type,
5175 get_coro_frame_align_bytes(g), false);
5176
5177 ConstExprValue *zero_array = create_const_str_lit(g, buf_create_from_str(""));
5178 ConstExprValue *undef_slice_zero = create_const_slice(g, zero_array, 0, 0, false);
5179 render_const_val(g, undef_slice_zero, "");
5180 render_const_val_global(g, undef_slice_zero, "");
5181
5182 ZigList<LLVMValueRef> args = {};
5183 args.append(sret_ptr);
5184 if (g->have_err_ret_tracing) {
5185 args.append(stack_trace_val);
5186 }
5187 args.append(allocator_val);
5188 args.append(undef_slice_zero->global_refs->llvm_global);
5189 args.append(LLVMGetUndef(g->builtin_types.entry_u29->llvm_type));
5190 args.append(coro_size);
5191 args.append(alignment_val);
5192 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, realloc_fn_val, args.items, args.length,
5193 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5194 set_call_instr_sret(g, call_instruction);
5195 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");
5196 LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
5197 LLVMBuildStore(g->builder, err_val, err_code_ptr);
5198 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, LLVMConstNull(LLVMTypeOf(err_val)), "");
5199 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "AllocOk");
5200 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "AllocFail");
5201 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
5202
5203 LLVMPositionBuilderAtEnd(g->builder, ok_block);
5204 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
5205 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
5206 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
5207 ZigType *slice_type = get_slice_type(g, u8_ptr_type);
5208 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5209 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
5210 LLVMValueRef ptr_val = LLVMBuildLoad(g->builder, ptr_field_ptr, "");
5211 LLVMBuildRet(g->builder, ptr_val);
5212
5213 LLVMPositionBuilderAtEnd(g->builder, fail_block);
5214 LLVMBuildRet(g->builder, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)));
5215
5216 g->cur_fn = prev_cur_fn;
5217 g->cur_fn_val = prev_cur_fn_val;
5218 LLVMPositionBuilderAtEnd(g->builder, prev_block);
5219 if (!g->strip_debug_symbols) {
5220 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
5221 }
5222
5223 g->coro_alloc_helper_fn_val = fn_val;
5224 return fn_val;
5225}
5226
5227static LLVMValueRef ir_render_coro_alloc_helper(CodeGen *g, IrExecutable *executable,
5228 IrInstructionCoroAllocHelper *instruction)
5229{
5230 LLVMValueRef realloc_fn = ir_llvm_value(g, instruction->realloc_fn);
5231 LLVMValueRef coro_size = ir_llvm_value(g, instruction->coro_size);
5232 LLVMValueRef fn_val = get_coro_alloc_helper_fn_val(g, LLVMTypeOf(realloc_fn), instruction->realloc_fn->value.type);
5233 size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
5234 size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
5235
5236 ZigList<LLVMValueRef> params = {};
5237 params.append(realloc_fn);
5238 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, g->cur_fn);
5239 if (err_ret_trace_arg_index != UINT32_MAX) {
5240 params.append(LLVMGetParam(g->cur_fn_val, err_ret_trace_arg_index));
5241 }
5242 params.append(LLVMGetParam(g->cur_fn_val, allocator_arg_index));
5243 params.append(LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index));
5244 params.append(coro_size);
5245
5246 return ZigLLVMBuildCall(g->builder, fn_val, params.items, params.length,
5247 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5248}
5249
52505311static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
52515312 IrInstructionAtomicRmw *instruction)
52525313{
......@@ -5263,14 +5324,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
52635324 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
52645325
52655326 if (get_codegen_ptr_type(operand_type) == nullptr) {
5266 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, false);
5327 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
52675328 }
52685329
52695330 // it's a pointer but we need to treat it as an int
52705331 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
52715332 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
52725333 LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, "");
5273 LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, false);
5334 LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
5335 g->is_single_threaded);
52745336 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
52755337}
52765338
......@@ -5284,27 +5346,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
52845346 return load_inst;
52855347}
52865348
5287static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
5288 IrInstructionMergeErrRetTraces *instruction)
5289{
5290 assert(g->have_err_ret_tracing);
5291
5292 LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
5293 LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
5294
5295 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5296 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5297 return nullptr;
5298}
5299
5300static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable,
5301 IrInstructionMarkErrRetTracePtr *instruction)
5302{
5303 assert(g->have_err_ret_tracing);
5304 g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr);
5305 return nullptr;
5306}
5307
53085349static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
53095350 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
53105351 assert(instruction->base.value.type->id == ZigTypeIdFloat);
......@@ -5424,6 +5465,174 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
54245465 return nullptr;
54255466}
54265467
5468static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable,
5469 IrInstructionSuspendBegin *instruction)
5470{
5471 instruction->resume_bb = gen_suspend_begin(g, "SuspendResume");
5472 return nullptr;
5473}
5474
5475static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executable,
5476 IrInstructionSuspendFinish *instruction)
5477{
5478 LLVMBuildRetVoid(g->builder);
5479
5480 LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb);
5481 render_async_var_decls(g, instruction->base.scope);
5482 return nullptr;
5483}
5484
5485static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {
5486 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5487 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
5488 LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame);
5489 ZigType *result_type = instruction->base.value.type;
5490 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
5491
5492 // Prepare to be suspended
5493 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");
5494 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");
5495
5496 // At this point resuming the function will continue from resume_bb.
5497 // This code is as if it is running inside the suspend block.
5498
5499 // supply the awaiter return pointer
5500 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
5501 nullptr : ir_llvm_value(g, instruction->result_loc);
5502 if (type_has_bits(result_type)) {
5503 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");
5504 if (result_loc == nullptr) {
5505 // no copy needed
5506 LLVMBuildStore(g->builder, LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr_ptr))),
5507 awaiter_ret_ptr_ptr);
5508 } else {
5509 LLVMBuildStore(g->builder, result_loc, awaiter_ret_ptr_ptr);
5510 }
5511 }
5512
5513 // supply the error return trace pointer
5514 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5515 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
5516 assert(my_err_ret_trace_val != nullptr);
5517 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5518 frame_index_trace_arg(g, result_type) + 1, "");
5519 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
5520 }
5521
5522 // caller's own frame pointer
5523 LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, "");
5524 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_awaiter_index, "");
5525 LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val,
5526 LLVMAtomicOrderingRelease);
5527
5528 LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait");
5529 LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend");
5530 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
5531
5532 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
5533 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2);
5534
5535 LLVMAddCase(switch_instr, zero, complete_suspend_block);
5536 LLVMAddCase(switch_instr, all_ones, early_return_block);
5537
5538 // We discovered that another awaiter was already here.
5539 LLVMPositionBuilderAtEnd(g->builder, bad_await_block);
5540 gen_assertion(g, PanicMsgIdBadAwait, &instruction->base);
5541
5542 // Rely on the target to resume us from suspension.
5543 LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block);
5544 LLVMBuildRetVoid(g->builder);
5545
5546 // Early return: The async function has already completed. We must copy the result and
5547 // the error return trace if applicable.
5548 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5549 if (type_has_bits(result_type) && result_loc != nullptr) {
5550 LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, "");
5551 LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, "");
5552 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
5553 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, "");
5554 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, "");
5555 bool is_volatile = false;
5556 uint32_t abi_align = get_abi_alignment(g, result_type);
5557 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false);
5558 ZigLLVMBuildMemCpy(g->builder,
5559 dest_ptr_casted, abi_align,
5560 src_ptr_casted, abi_align, byte_count_val, is_volatile);
5561 }
5562 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5563 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5564 frame_index_trace_arg(g, result_type), "");
5565 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5566 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
5567 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5568 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5569 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5570 }
5571 LLVMBuildBr(g->builder, end_bb);
5572
5573 LLVMPositionBuilderAtEnd(g->builder, resume_bb);
5574 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
5575 LLVMBuildBr(g->builder, end_bb);
5576
5577 LLVMPositionBuilderAtEnd(g->builder, end_bb);
5578 if (type_has_bits(result_type) && result_loc != nullptr) {
5579 return get_handle_value(g, result_loc, result_type, ptr_result_type);
5580 }
5581 return nullptr;
5582}
5583
5584static LLVMValueRef ir_render_resume(CodeGen *g, IrExecutable *executable, IrInstructionResume *instruction) {
5585 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);
5586 ZigType *frame_type = instruction->frame->value.type;
5587 assert(frame_type->id == ZigTypeIdAnyFrame);
5588
5589 gen_resume(g, nullptr, frame, ResumeIdManual);
5590 return nullptr;
5591}
5592
5593static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,
5594 IrInstructionFrameSizeGen *instruction)
5595{
5596 LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
5597 return gen_frame_size(g, fn_val);
5598}
5599
5600static LLVMValueRef ir_render_spill_begin(CodeGen *g, IrExecutable *executable,
5601 IrInstructionSpillBegin *instruction)
5602{
5603 if (!fn_is_async(g->cur_fn))
5604 return nullptr;
5605
5606 switch (instruction->spill_id) {
5607 case SpillIdInvalid:
5608 zig_unreachable();
5609 case SpillIdRetErrCode: {
5610 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
5611 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5612 LLVMBuildStore(g->builder, operand, ptr);
5613 return nullptr;
5614 }
5615
5616 }
5617 zig_unreachable();
5618}
5619
5620static LLVMValueRef ir_render_spill_end(CodeGen *g, IrExecutable *executable, IrInstructionSpillEnd *instruction) {
5621 if (!fn_is_async(g->cur_fn))
5622 return ir_llvm_value(g, instruction->begin->operand);
5623
5624 switch (instruction->begin->spill_id) {
5625 case SpillIdInvalid:
5626 zig_unreachable();
5627 case SpillIdRetErrCode: {
5628 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5629 return LLVMBuildLoad(g->builder, ptr, "");
5630 }
5631
5632 }
5633 zig_unreachable();
5634}
5635
54275636static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
54285637 AstNode *source_node = instruction->source_node;
54295638 Scope *scope = instruction->scope;
......@@ -5445,7 +5654,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54455654 case IrInstructionIdSetRuntimeSafety:
54465655 case IrInstructionIdSetFloatMode:
54475656 case IrInstructionIdArrayType:
5448 case IrInstructionIdPromiseType:
5657 case IrInstructionIdAnyFrameType:
54495658 case IrInstructionIdSliceType:
54505659 case IrInstructionIdSizeOf:
54515660 case IrInstructionIdSwitchTarget:
......@@ -5485,8 +5694,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54855694 case IrInstructionIdTagType:
54865695 case IrInstructionIdExport:
54875696 case IrInstructionIdErrorUnion:
5488 case IrInstructionIdPromiseResultType:
5489 case IrInstructionIdAwaitBookkeeping:
54905697 case IrInstructionIdAddImplicitReturnType:
54915698 case IrInstructionIdIntCast:
54925699 case IrInstructionIdFloatCast:
......@@ -5508,17 +5715,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55085715 case IrInstructionIdCallSrc:
55095716 case IrInstructionIdAllocaSrc:
55105717 case IrInstructionIdEndExpr:
5511 case IrInstructionIdAllocaGen:
55125718 case IrInstructionIdImplicitCast:
55135719 case IrInstructionIdResolveResult:
55145720 case IrInstructionIdResetResult:
5515 case IrInstructionIdResultPtr:
55165721 case IrInstructionIdContainerInitList:
55175722 case IrInstructionIdSliceSrc:
55185723 case IrInstructionIdRef:
55195724 case IrInstructionIdBitCastSrc:
55205725 case IrInstructionIdTestErrSrc:
55215726 case IrInstructionIdUnionInitNamedField:
5727 case IrInstructionIdFrameType:
5728 case IrInstructionIdFrameSizeSrc:
5729 case IrInstructionIdAllocaGen:
5730 case IrInstructionIdAwaitSrc:
55225731 zig_unreachable();
55235732
55245733 case IrInstructionIdDeclVarGen:
......@@ -5597,8 +5806,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55975806 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
55985807 case IrInstructionIdFrameAddress:
55995808 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
5600 case IrInstructionIdHandle:
5601 return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
5809 case IrInstructionIdFrameHandle:
5810 return ir_render_handle(g, executable, (IrInstructionFrameHandle *)instruction);
56025811 case IrInstructionIdOverflowOp:
56035812 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
56045813 case IrInstructionIdTestErrGen:
......@@ -5641,44 +5850,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
56415850 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
56425851 case IrInstructionIdErrorReturnTrace:
56435852 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
5644 case IrInstructionIdCancel:
5645 return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction);
5646 case IrInstructionIdGetImplicitAllocator:
5647 return ir_render_get_implicit_allocator(g, executable, (IrInstructionGetImplicitAllocator *)instruction);
5648 case IrInstructionIdCoroId:
5649 return ir_render_coro_id(g, executable, (IrInstructionCoroId *)instruction);
5650 case IrInstructionIdCoroAlloc:
5651 return ir_render_coro_alloc(g, executable, (IrInstructionCoroAlloc *)instruction);
5652 case IrInstructionIdCoroSize:
5653 return ir_render_coro_size(g, executable, (IrInstructionCoroSize *)instruction);
5654 case IrInstructionIdCoroBegin:
5655 return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);
5656 case IrInstructionIdCoroAllocFail:
5657 return ir_render_coro_alloc_fail(g, executable, (IrInstructionCoroAllocFail *)instruction);
5658 case IrInstructionIdCoroSuspend:
5659 return ir_render_coro_suspend(g, executable, (IrInstructionCoroSuspend *)instruction);
5660 case IrInstructionIdCoroEnd:
5661 return ir_render_coro_end(g, executable, (IrInstructionCoroEnd *)instruction);
5662 case IrInstructionIdCoroFree:
5663 return ir_render_coro_free(g, executable, (IrInstructionCoroFree *)instruction);
5664 case IrInstructionIdCoroResume:
5665 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
5666 case IrInstructionIdCoroSave:
5667 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
5668 case IrInstructionIdCoroPromise:
5669 return ir_render_coro_promise(g, executable, (IrInstructionCoroPromise *)instruction);
5670 case IrInstructionIdCoroAllocHelper:
5671 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
56725853 case IrInstructionIdAtomicRmw:
56735854 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
56745855 case IrInstructionIdAtomicLoad:
56755856 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
56765857 case IrInstructionIdSaveErrRetAddr:
56775858 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
5678 case IrInstructionIdMergeErrRetTraces:
5679 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
5680 case IrInstructionIdMarkErrRetTracePtr:
5681 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
56825859 case IrInstructionIdFloatOp:
56835860 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
56845861 case IrInstructionIdMulAdd:
......@@ -5695,6 +5872,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
56955872 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
56965873 case IrInstructionIdPtrOfArrayToSlice:
56975874 return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction);
5875 case IrInstructionIdSuspendBegin:
5876 return ir_render_suspend_begin(g, executable, (IrInstructionSuspendBegin *)instruction);
5877 case IrInstructionIdSuspendFinish:
5878 return ir_render_suspend_finish(g, executable, (IrInstructionSuspendFinish *)instruction);
5879 case IrInstructionIdResume:
5880 return ir_render_resume(g, executable, (IrInstructionResume *)instruction);
5881 case IrInstructionIdFrameSizeGen:
5882 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);
5883 case IrInstructionIdAwaitGen:
5884 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
5885 case IrInstructionIdSpillBegin:
5886 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
5887 case IrInstructionIdSpillEnd:
5888 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
56985889 }
56995890 zig_unreachable();
57005891}
......@@ -5704,6 +5895,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
57045895
57055896 IrExecutable *executable = &fn_entry->analyzed_executable;
57065897 assert(executable->basic_block_list.length > 0);
5898
57075899 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
57085900 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
57095901 assert(current_block->llvm_block);
......@@ -5894,7 +6086,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
58946086 case ZigTypeIdPointer:
58956087 case ZigTypeIdFn:
58966088 case ZigTypeIdOptional:
5897 case ZigTypeIdPromise:
58986089 {
58996090 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
59006091 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type);
......@@ -5957,7 +6148,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
59576148 }
59586149 return val;
59596150 }
5960
6151 case ZigTypeIdFnFrame:
6152 zig_panic("TODO bit pack an async function frame");
6153 case ZigTypeIdAnyFrame:
6154 zig_panic("TODO bit pack an anyframe");
59616155 }
59626156 zig_unreachable();
59636157}
......@@ -6110,6 +6304,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
61106304 break;
61116305 }
61126306
6307 if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull)))
6308 zig_unreachable();
6309
61136310 switch (type_entry->id) {
61146311 case ZigTypeIdInt:
61156312 return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint);
......@@ -6181,6 +6378,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
61816378 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
61826379 size_t src_field_count = type_entry->data.structure.src_field_count;
61836380 bool make_unnamed_struct = false;
6381 assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull);
61846382 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
61856383 size_t src_field_index = 0;
61866384 while (src_field_index < src_field_count) {
......@@ -6250,6 +6448,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
62506448 LLVMValueRef val = gen_const_val(g, field_val, "");
62516449 fields[type_struct_field->gen_index] = val;
62526450 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
6451
6452 size_t end_pad_gen_index = (i + 1 < src_field_count) ?
6453 type_entry->data.structure.fields[i + 1].gen_index :
6454 type_entry->data.structure.gen_field_count;
6455 size_t next_offset = (i + 1 < src_field_count) ?
6456 type_entry->data.structure.fields[i + 1].offset : type_entry->abi_size;
6457 if (end_pad_gen_index != SIZE_MAX) {
6458 for (size_t gen_i = type_struct_field->gen_index + 1; gen_i < end_pad_gen_index;
6459 gen_i += 1)
6460 {
6461 size_t pad_bytes = next_offset -
6462 (type_struct_field->offset + type_struct_field->type_entry->abi_size);
6463 LLVMTypeRef llvm_array_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
6464 fields[gen_i] = LLVMGetUndef(llvm_array_type);
6465 }
6466 }
62536467 }
62546468 }
62556469 if (make_unnamed_struct) {
......@@ -6437,13 +6651,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
64376651 err_payload_value = gen_const_val(g, payload_val, "");
64386652 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);
64396653 }
6440 LLVMValueRef fields[2];
6654 LLVMValueRef fields[3];
64416655 fields[err_union_err_index] = err_tag_value;
64426656 fields[err_union_payload_index] = err_payload_value;
6657 size_t field_count = 2;
6658 if (type_entry->data.error_union.pad_llvm_type != nullptr) {
6659 fields[2] = LLVMGetUndef(type_entry->data.error_union.pad_llvm_type);
6660 field_count = 3;
6661 }
64436662 if (make_unnamed_struct) {
6444 return LLVMConstStruct(fields, 2, false);
6663 return LLVMConstStruct(fields, field_count, false);
64456664 } else {
6446 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
6665 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count);
64476666 }
64486667 }
64496668 }
......@@ -6460,9 +6679,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
64606679 case ZigTypeIdBoundFn:
64616680 case ZigTypeIdArgTuple:
64626681 case ZigTypeIdOpaque:
6463 case ZigTypeIdPromise:
64646682 zig_unreachable();
6465
6683 case ZigTypeIdFnFrame:
6684 zig_panic("TODO");
6685 case ZigTypeIdAnyFrame:
6686 zig_panic("TODO");
64666687 }
64676688 zig_unreachable();
64686689}
......@@ -6546,12 +6767,20 @@ static void generate_error_name_table(CodeGen *g) {
65466767static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {
65476768 IrExecutable *executable = &fn->analyzed_executable;
65486769 assert(executable->basic_block_list.length > 0);
6770 LLVMValueRef fn_val = fn_llvm_value(g, fn);
6771 LLVMBasicBlockRef first_bb = nullptr;
6772 if (fn_is_async(fn)) {
6773 first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch");
6774 g->cur_preamble_llvm_block = first_bb;
6775 }
65496776 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
65506777 IrBasicBlock *bb = executable->basic_block_list.at(block_i);
6551 bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint);
6778 bb->llvm_block = LLVMAppendBasicBlock(fn_val, bb->name_hint);
6779 }
6780 if (first_bb == nullptr) {
6781 first_bb = executable->basic_block_list.at(0)->llvm_block;
65526782 }
6553 IrBasicBlock *entry_bb = executable->basic_block_list.at(0);
6554 LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
6783 LLVMPositionBuilderAtEnd(g->builder, first_bb);
65556784}
65566785
65576786static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
......@@ -6728,13 +6957,19 @@ static void do_code_gen(CodeGen *g) {
67286957 build_all_basic_blocks(g, fn_table_entry);
67296958 clear_debug_source_node(g);
67306959
6731 if (want_sret) {
6732 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6733 } else if (handle_is_ptr(fn_type_id->return_type)) {
6734 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
6735 // TODO add debug info variable for this
6960 bool is_async = fn_is_async(fn_table_entry);
6961
6962 if (is_async) {
6963 g->cur_frame_ptr = LLVMGetParam(fn, 0);
67366964 } else {
6737 g->cur_ret_ptr = nullptr;
6965 if (want_sret) {
6966 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6967 } else if (handle_is_ptr(fn_type_id->return_type)) {
6968 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
6969 // TODO add debug info variable for this
6970 } else {
6971 g->cur_ret_ptr = nullptr;
6972 }
67386973 }
67396974
67406975 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
......@@ -6746,39 +6981,41 @@ static void do_code_gen(CodeGen *g) {
67466981 }
67476982
67486983 // error return tracing setup
6749 bool is_async = cc == CallingConventionAsync;
6750 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
6984 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
6985 !is_async && !have_err_ret_trace_arg;
67516986 LLVMValueRef err_ret_array_val = nullptr;
67526987 if (have_err_ret_trace_stack) {
67536988 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
67546989 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
67556990
6756 // populate g->stack_trace_type
6757 (void)get_ptr_to_stack_trace_type(g);
6758 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
6991 (void)get_llvm_type(g, get_stack_trace_type(g));
6992 g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace",
6993 get_abi_alignment(g, g->stack_trace_type));
67596994 } else {
67606995 g->cur_err_ret_trace_val_stack = nullptr;
67616996 }
67626997
6763 // allocate temporary stack data
6764 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6765 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6766 ZigType *ptr_type = instruction->base.value.type;
6767 assert(ptr_type->id == ZigTypeIdPointer);
6768 ZigType *child_type = ptr_type->data.pointer.child_type;
6769 if (!type_has_bits(child_type))
6770 continue;
6771 if (instruction->base.ref_count == 0)
6772 continue;
6773 if (instruction->base.value.special != ConstValSpecialRuntime) {
6774 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
6775 ConstValSpecialRuntime)
6776 {
6998 if (!is_async) {
6999 // allocate temporary stack data
7000 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
7001 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
7002 ZigType *ptr_type = instruction->base.value.type;
7003 assert(ptr_type->id == ZigTypeIdPointer);
7004 ZigType *child_type = ptr_type->data.pointer.child_type;
7005 if (!type_has_bits(child_type))
67777006 continue;
7007 if (instruction->base.ref_count == 0)
7008 continue;
7009 if (instruction->base.value.special != ConstValSpecialRuntime) {
7010 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
7011 ConstValSpecialRuntime)
7012 {
7013 continue;
7014 }
67787015 }
7016 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
7017 get_ptr_align(g, ptr_type));
67797018 }
6780 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6781 get_ptr_align(g, ptr_type));
67827019 }
67837020
67847021 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
......@@ -6816,7 +7053,7 @@ static void do_code_gen(CodeGen *g) {
68167053 } else if (is_c_abi) {
68177054 fn_walk_var.data.vars.var = var;
68187055 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
6819 } else {
7056 } else if (!is_async) {
68207057 ZigType *gen_type;
68217058 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
68227059 assert(gen_info->gen_index != SIZE_MAX);
......@@ -6867,14 +7104,76 @@ static void do_code_gen(CodeGen *g) {
68677104 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
68687105 }
68697106
6870 // create debug variable declarations for parameters
6871 // rely on the first variables in the variable_list being parameters.
6872 FnWalk fn_walk_init = {};
6873 fn_walk_init.id = FnWalkIdInits;
6874 fn_walk_init.data.inits.fn = fn_table_entry;
6875 fn_walk_init.data.inits.llvm_fn = fn;
6876 fn_walk_init.data.inits.gen_i = gen_i_init;
6877 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
7107 if (is_async) {
7108 (void)get_llvm_type(g, fn_table_entry->frame_type);
7109 g->cur_resume_block_count = 0;
7110
7111 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
7112 LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
7113 ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
7114
7115 if (!g->strip_debug_symbols) {
7116 AstNode *source_node = fn_table_entry->proto_node;
7117 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
7118 (int)source_node->column + 1, get_di_scope(g, fn_table_entry->child_scope));
7119 }
7120 IrExecutable *executable = &fn_table_entry->analyzed_executable;
7121 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
7122 LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
7123 gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope);
7124
7125 LLVMPositionBuilderAtEnd(g->builder, g->cur_preamble_llvm_block);
7126 render_async_spills(g);
7127 g->cur_async_awaiter_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_awaiter_index, "");
7128 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_resume_index, "");
7129 g->cur_async_resume_index_ptr = resume_index_ptr;
7130
7131 if (type_has_bits(fn_type_id->return_type)) {
7132 LLVMValueRef cur_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start, "");
7133 g->cur_ret_ptr = LLVMBuildLoad(g->builder, cur_ret_ptr_ptr, "");
7134 }
7135 uint32_t trace_field_index_stack = UINT32_MAX;
7136 if (codegen_fn_has_err_ret_tracing_stack(g, fn_table_entry, true)) {
7137 trace_field_index_stack = frame_index_trace_stack(g, fn_type_id);
7138 g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7139 trace_field_index_stack, "");
7140 }
7141
7142 LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, "");
7143 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4);
7144 g->cur_async_switch_instr = switch_instr;
7145
7146 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
7147 IrBasicBlock *entry_block = executable->basic_block_list.at(0);
7148 LLVMAddCase(switch_instr, zero, entry_block->llvm_block);
7149 g->cur_resume_block_count += 1;
7150 LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block);
7151 if (trace_field_index_stack != UINT32_MAX) {
7152 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
7153 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7154 frame_index_trace_arg(g, fn_type_id->return_type), "");
7155 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(trace_ptr_ptr)));
7156 LLVMBuildStore(g->builder, zero_ptr, trace_ptr_ptr);
7157 }
7158
7159 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7160 trace_field_index_stack, "");
7161 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7162 trace_field_index_stack + 1, "");
7163
7164 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
7165 }
7166 render_async_var_decls(g, entry_block->instruction_list.at(0)->scope);
7167 } else {
7168 // create debug variable declarations for parameters
7169 // rely on the first variables in the variable_list being parameters.
7170 FnWalk fn_walk_init = {};
7171 fn_walk_init.id = FnWalkIdInits;
7172 fn_walk_init.data.inits.fn = fn_table_entry;
7173 fn_walk_init.data.inits.llvm_fn = fn;
7174 fn_walk_init.data.inits.gen_i = gen_i_init;
7175 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
7176 }
68787177
68797178 ir_render(g, fn_table_entry);
68807179
......@@ -6893,8 +7192,6 @@ static void do_code_gen(CodeGen *g) {
68937192 LLVMDumpModule(g->module);
68947193 }
68957194
6896 // in release mode, we're sooooo confident that we've generated correct ir,
6897 // that we skip the verify module step in order to get better performance.
68987195#ifndef NDEBUG
68997196 char *error = nullptr;
69007197 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
......@@ -7163,16 +7460,8 @@ static void define_builtin_types(CodeGen *g) {
71637460
71647461 g->primitive_type_table.put(&entry->name, entry);
71657462 }
7166 {
7167 ZigType *entry = get_promise_type(g, nullptr);
7168 g->primitive_type_table.put(&entry->name, entry);
7169 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
7170 entry->abi_align = g->builtin_types.entry_usize->abi_align;
7171 entry->abi_size = g->builtin_types.entry_usize->abi_size;
7172 }
71737463}
71747464
7175
71767465static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {
71777466 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
71787467 buf_init_from_str(&builtin_fn->name, name);
......@@ -7185,8 +7474,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
71857474static void define_builtin_fns(CodeGen *g) {
71867475 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
71877476 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
7188 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7189 create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
71907477 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
71917478 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
71927479 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
......@@ -7262,13 +7549,13 @@ static void define_builtin_fns(CodeGen *g) {
72627549 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
72637550 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
72647551 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7265 //Needs library support on Windows
7266 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7552 create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
72677553 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
72687554 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
72697555 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
72707556 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
72717557 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
7558 create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
72727559 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
72737560 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
72747561 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
......@@ -7287,6 +7574,10 @@ static void define_builtin_fns(CodeGen *g) {
72877574 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
72887575 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
72897576 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);
7577 create_builtin_fn(g, BuiltinFnIdFrameHandle, "frame", 0);
7578 create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1);
7579 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7580 create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
72907581}
72917582
72927583static const char *bool_to_str(bool b) {
......@@ -7598,7 +7889,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75987889 " BoundFn: Fn,\n"
75997890 " ArgTuple: void,\n"
76007891 " Opaque: void,\n"
7601 " Promise: Promise,\n"
7892 " Frame: void,\n"
7893 " AnyFrame: AnyFrame,\n"
76027894 " Vector: Vector,\n"
76037895 " EnumLiteral: void,\n"
76047896 "\n\n"
......@@ -7711,11 +8003,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
77118003 " is_generic: bool,\n"
77128004 " is_var_args: bool,\n"
77138005 " return_type: ?type,\n"
7714 " async_allocator_type: ?type,\n"
77158006 " args: []FnArg,\n"
77168007 " };\n"
77178008 "\n"
7718 " pub const Promise = struct {\n"
8009 " pub const AnyFrame = struct {\n"
77198010 " child: ?type,\n"
77208011 " };\n"
77218012 "\n"
......@@ -8308,6 +8599,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83088599 args.append("-g");
83098600 }
83108601
8602 if (codegen_have_frame_pointer(g)) {
8603 args.append("-fno-omit-frame-pointer");
8604 } else {
8605 args.append("-fomit-frame-pointer");
8606 }
8607
83118608 switch (g->build_mode) {
83128609 case BuildModeDebug:
83138610 // windows c runtime requires -D_DEBUG if using debug libraries
......@@ -8320,7 +8617,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83208617 } else {
83218618 args.append("-fno-stack-protector");
83228619 }
8323 args.append("-fno-omit-frame-pointer");
83248620 break;
83258621 case BuildModeSafeRelease:
83268622 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
......@@ -8334,7 +8630,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83348630 } else {
83358631 args.append("-fno-stack-protector");
83368632 }
8337 args.append("-fomit-frame-pointer");
83388633 break;
83398634 case BuildModeFastRelease:
83408635 args.append("-DNDEBUG");
......@@ -8345,13 +8640,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83458640 // running in -O2 and thus the -O3 path has been tested less.
83468641 args.append("-O2");
83478642 args.append("-fno-stack-protector");
8348 args.append("-fomit-frame-pointer");
83498643 break;
83508644 case BuildModeSmallRelease:
83518645 args.append("-DNDEBUG");
83528646 args.append("-Os");
83538647 args.append("-fno-stack-protector");
8354 args.append("-fomit-frame-pointer");
83558648 break;
83568649 }
83578650
......@@ -8878,7 +9171,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
88789171 case ZigTypeIdArgTuple:
88799172 case ZigTypeIdErrorUnion:
88809173 case ZigTypeIdErrorSet:
8881 case ZigTypeIdPromise:
9174 case ZigTypeIdFnFrame:
9175 case ZigTypeIdAnyFrame:
88829176 zig_unreachable();
88839177 case ZigTypeIdVoid:
88849178 case ZigTypeIdUnreachable:
......@@ -9062,7 +9356,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
90629356 case ZigTypeIdUndefined:
90639357 case ZigTypeIdNull:
90649358 case ZigTypeIdArgTuple:
9065 case ZigTypeIdPromise:
9359 case ZigTypeIdFnFrame:
9360 case ZigTypeIdAnyFrame:
90669361 zig_unreachable();
90679362 }
90689363}
......@@ -9229,9 +9524,11 @@ static void gen_h_file(CodeGen *g) {
92299524 case ZigTypeIdArgTuple:
92309525 case ZigTypeIdOptional:
92319526 case ZigTypeIdFn:
9232 case ZigTypeIdPromise:
92339527 case ZigTypeIdVector:
9528 case ZigTypeIdFnFrame:
9529 case ZigTypeIdAnyFrame:
92349530 zig_unreachable();
9531
92359532 case ZigTypeIdEnum:
92369533 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
92379534 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));
......@@ -9770,3 +10067,18 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
977010067 return g;
977110068}
977210069
10070bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type) {
10071 return g->have_err_ret_tracing &&
10072 (return_type->id == ZigTypeIdErrorUnion ||
10073 return_type->id == ZigTypeIdErrorSet);
10074}
10075
10076bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async) {
10077 if (is_async) {
10078 return g->have_err_ret_tracing && (fn->calls_or_awaits_errorable_fn ||
10079 codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type));
10080 } else {
10081 return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn &&
10082 !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type);
10083 }
10084}
src/codegen.hpp+2
......@@ -61,5 +61,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g);
6161TargetSubsystem detect_subsystem(CodeGen *g);
6262
6363void codegen_release_caches(CodeGen *codegen);
64bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type);
65bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async);
6466
6567#endif
src/ir.cpp+853-1711
......@@ -26,6 +26,7 @@ struct IrBuilder {
2626 CodeGen *codegen;
2727 IrExecutable *exec;
2828 IrBasicBlock *current_basic_block;
29 AstNode *main_block_node;
2930};
3031
3132struct IrAnalyze {
......@@ -99,7 +100,6 @@ struct ConstCastOnly {
99100 ConstCastErrUnionErrSetMismatch *error_union_error_set;
100101 ConstCastTypeMismatch *type_mismatch;
101102 ConstCastOnly *return_type;
102 ConstCastOnly *async_allocator_type;
103103 ConstCastOnly *null_wrap_ptr_child;
104104 ConstCastArg fn_arg;
105105 ConstCastArgNoAlias arg_no_alias;
......@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
305305 case ZigTypeIdBoundFn:
306306 case ZigTypeIdErrorSet:
307307 case ZigTypeIdOpaque:
308 case ZigTypeIdAnyFrame:
308309 return true;
309310 case ZigTypeIdFloat:
310311 return a->data.floating.bit_count == b->data.floating.bit_count;
......@@ -319,8 +320,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
319320 case ZigTypeIdUnion:
320321 case ZigTypeIdFn:
321322 case ZigTypeIdArgTuple:
322 case ZigTypeIdPromise:
323323 case ZigTypeIdVector:
324 case ZigTypeIdFnFrame:
324325 return false;
325326 }
326327 zig_unreachable();
......@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
565566 return IrInstructionIdArrayType;
566567}
567568
568static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
569 return IrInstructionIdPromiseType;
569static constexpr IrInstructionId ir_instruction_id(IrInstructionAnyFrameType *) {
570 return IrInstructionIdAnyFrameType;
570571}
571572
572573static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
......@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
761762 return IrInstructionIdFrameAddress;
762763}
763764
764static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {
765 return IrInstructionIdHandle;
765static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameHandle *) {
766 return IrInstructionIdFrameHandle;
767}
768
769static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameType *) {
770 return IrInstructionIdFrameType;
771}
772
773static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeSrc *) {
774 return IrInstructionIdFrameSizeSrc;
775}
776
777static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeGen *) {
778 return IrInstructionIdFrameSizeGen;
766779}
767780
768781static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
......@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {
933946 return IrInstructionIdResetResult;
934947}
935948
936static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) {
937 return IrInstructionIdResultPtr;
938}
939
940949static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
941950 return IrInstructionIdPtrOfArrayToSlice;
942951}
......@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
961970 return IrInstructionIdErrorUnion;
962971}
963972
964static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) {
965 return IrInstructionIdCancel;
966}
967
968static constexpr IrInstructionId ir_instruction_id(IrInstructionGetImplicitAllocator *) {
969 return IrInstructionIdGetImplicitAllocator;
970}
971
972static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroId *) {
973 return IrInstructionIdCoroId;
974}
975
976static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAlloc *) {
977 return IrInstructionIdCoroAlloc;
978}
979
980static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSize *) {
981 return IrInstructionIdCoroSize;
982}
983
984static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroBegin *) {
985 return IrInstructionIdCoroBegin;
986}
987
988static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *) {
989 return IrInstructionIdCoroAllocFail;
990}
991
992static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) {
993 return IrInstructionIdCoroSuspend;
994}
995
996static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) {
997 return IrInstructionIdCoroEnd;
998}
999
1000static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) {
1001 return IrInstructionIdCoroFree;
1002}
1003
1004static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
1005 return IrInstructionIdCoroResume;
1006}
1007
1008static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
1009 return IrInstructionIdCoroSave;
1010}
1011
1012static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
1013 return IrInstructionIdCoroPromise;
1014}
1015
1016static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
1017 return IrInstructionIdCoroAllocHelper;
1018}
1019
1020973static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
1021974 return IrInstructionIdAtomicRmw;
1022975}
......@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
1025978 return IrInstructionIdAtomicLoad;
1026979}
1027980
1028static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
1029 return IrInstructionIdPromiseResultType;
1030}
1031
1032static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping *) {
1033 return IrInstructionIdAwaitBookkeeping;
1034}
1035
1036981static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
1037982 return IrInstructionIdSaveErrRetAddr;
1038983}
......@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
1041986 return IrInstructionIdAddImplicitReturnType;
1042987}
1043988
1044static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
1045 return IrInstructionIdMergeErrRetTraces;
1046}
1047
1048static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
1049 return IrInstructionIdMarkErrRetTracePtr;
1050}
1051
1052989static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1053990 return IrInstructionIdFloatOp;
1054991}
......@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi
10971034 return IrInstructionIdUnionInitNamedField;
10981035}
10991036
1037static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBegin *) {
1038 return IrInstructionIdSuspendBegin;
1039}
1040
1041static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendFinish *) {
1042 return IrInstructionIdSuspendFinish;
1043}
1044
1045static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitSrc *) {
1046 return IrInstructionIdAwaitSrc;
1047}
1048
1049static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitGen *) {
1050 return IrInstructionIdAwaitGen;
1051}
1052
1053static constexpr IrInstructionId ir_instruction_id(IrInstructionResume *) {
1054 return IrInstructionIdResume;
1055}
1056
1057static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillBegin *) {
1058 return IrInstructionIdSpillBegin;
1059}
1060
1061static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
1062 return IrInstructionIdSpillEnd;
1063}
1064
11001065template<typename T>
11011066static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
11021067 T *special_instruction = allocate<T>(1);
......@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
11491114}
11501115
11511116static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,
1152 IrInstruction *return_value)
1117 IrInstruction *operand)
11531118{
11541119 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);
11551120 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
11561121 return_instruction->base.value.special = ConstValSpecialStatic;
1157 return_instruction->value = return_value;
1122 return_instruction->operand = operand;
11581123
1159 if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block);
1124 if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block);
11601125
11611126 return &return_instruction->base;
11621127}
......@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode
12141179 return &const_instruction->base;
12151180}
12161181
1217static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) {
1218 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
1219 const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8;
1220 const_instruction->base.value.special = ConstValSpecialStatic;
1221 bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value);
1222 return &const_instruction->base;
1223}
1224
12251182static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
12261183 ZigType *type_entry)
12271184{
......@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
14291386
14301387static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
14311388 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1432 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1389 bool is_comptime, FnInline fn_inline, bool is_async,
14331390 IrInstruction *new_stack, ResultLoc *result_loc)
14341391{
14351392 IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);
......@@ -1440,22 +1397,24 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
14401397 call_instruction->args = args;
14411398 call_instruction->arg_count = arg_count;
14421399 call_instruction->is_async = is_async;
1443 call_instruction->async_allocator = async_allocator;
14441400 call_instruction->new_stack = new_stack;
14451401 call_instruction->result_loc = result_loc;
14461402
14471403 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
14481404 for (size_t i = 0; i < arg_count; i += 1)
14491405 ir_ref_instruction(args[i], irb->current_basic_block);
1450 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
1406 if (is_async && new_stack != nullptr) {
1407 // in this case the arg at the end is the return pointer
1408 ir_ref_instruction(args[arg_count], irb->current_basic_block);
1409 }
14511410 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
14521411
14531412 return &call_instruction->base;
14541413}
14551414
1456static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
1415static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
14571416 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1458 FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack,
1417 FnInline fn_inline, bool is_async, IrInstruction *new_stack,
14591418 IrInstruction *result_loc, ZigType *return_type)
14601419{
14611420 IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,
......@@ -1467,18 +1426,16 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in
14671426 call_instruction->args = args;
14681427 call_instruction->arg_count = arg_count;
14691428 call_instruction->is_async = is_async;
1470 call_instruction->async_allocator = async_allocator;
14711429 call_instruction->new_stack = new_stack;
14721430 call_instruction->result_loc = result_loc;
14731431
14741432 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);
14751433 for (size_t i = 0; i < arg_count; i += 1)
14761434 ir_ref_instruction(args[i], ira->new_irb.current_basic_block);
1477 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block);
14781435 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);
14791436 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
14801437
1481 return &call_instruction->base;
1438 return call_instruction;
14821439}
14831440
14841441static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,
......@@ -1754,17 +1711,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
17541711 return &instruction->base;
17551712}
17561713
1757static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1714static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
17581715 IrInstruction *payload_type)
17591716{
1760 IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);
1717 IrInstructionAnyFrameType *instruction = ir_build_instruction<IrInstructionAnyFrameType>(irb, scope, source_node);
17611718 instruction->payload_type = payload_type;
17621719
17631720 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
17641721
17651722 return &instruction->base;
17661723}
1767
17681724static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
17691725 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
17701726{
......@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo
24432399}
24442400
24452401static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2446 IrInstructionHandle *instruction = ir_build_instruction<IrInstructionHandle>(irb, scope, source_node);
2402 IrInstructionFrameHandle *instruction = ir_build_instruction<IrInstructionFrameHandle>(irb, scope, source_node);
2403 return &instruction->base;
2404}
2405
2406static IrInstruction *ir_build_frame_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2407 IrInstructionFrameType *instruction = ir_build_instruction<IrInstructionFrameType>(irb, scope, source_node);
2408 instruction->fn = fn;
2409
2410 ir_ref_instruction(fn, irb->current_basic_block);
2411
2412 return &instruction->base;
2413}
2414
2415static IrInstruction *ir_build_frame_size_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2416 IrInstructionFrameSizeSrc *instruction = ir_build_instruction<IrInstructionFrameSizeSrc>(irb, scope, source_node);
2417 instruction->fn = fn;
2418
2419 ir_ref_instruction(fn, irb->current_basic_block);
2420
2421 return &instruction->base;
2422}
2423
2424static IrInstruction *ir_build_frame_size_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn)
2425{
2426 IrInstructionFrameSizeGen *instruction = ir_build_instruction<IrInstructionFrameSizeGen>(irb, scope, source_node);
2427 instruction->fn = fn;
2428
2429 ir_ref_instruction(fn, irb->current_basic_block);
2430
24472431 return &instruction->base;
24482432}
24492433
......@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s
25462530}
25472531
25482532static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
2549 IrInstruction *base_ptr, bool resolve_err_set)
2533 IrInstruction *base_ptr, bool resolve_err_set, bool base_ptr_is_payload)
25502534{
25512535 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);
25522536 instruction->base_ptr = base_ptr;
25532537 instruction->resolve_err_set = resolve_err_set;
2538 instruction->base_ptr_is_payload = base_ptr_is_payload;
25542539
25552540 ir_ref_instruction(base_ptr, irb->current_basic_block);
25562541
......@@ -2596,13 +2581,12 @@ static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope,
25962581
25972582static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
25982583 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
2599 IrInstruction *async_allocator_type_value, bool is_var_args)
2584 bool is_var_args)
26002585{
26012586 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
26022587 instruction->param_types = param_types;
26032588 instruction->align_value = align_value;
26042589 instruction->return_type = return_type;
2605 instruction->async_allocator_type_value = async_allocator_type_value;
26062590 instruction->is_var_args = is_var_args;
26072591
26082592 assert(source_node->type == NodeTypeFnProto);
......@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
26122596 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
26132597 }
26142598 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
2615 if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block);
26162599 ir_ref_instruction(return_type, irb->current_basic_block);
26172600
26182601 return &instruction->base;
......@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod
29942977 return &instruction->base;
29952978}
29962979
2997static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
2998 ResultLoc *result_loc, IrInstruction *result)
2999{
3000 IrInstructionResultPtr *instruction = ir_build_instruction<IrInstructionResultPtr>(irb, scope, source_node);
3001 instruction->result_loc = result_loc;
3002 instruction->result = result;
3003
3004 ir_ref_instruction(result, irb->current_basic_block);
3005
3006 return &instruction->base;
3007}
3008
30092980static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
30102981 IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
30112982
......@@ -3056,149 +3027,6 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
30563027 return &instruction->base;
30573028}
30583029
3059static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node,
3060 IrInstruction *target)
3061{
3062 IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
3063 instruction->target = target;
3064
3065 ir_ref_instruction(target, irb->current_basic_block);
3066
3067 return &instruction->base;
3068}
3069
3070static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node,
3071 ImplicitAllocatorId id)
3072{
3073 IrInstructionGetImplicitAllocator *instruction = ir_build_instruction<IrInstructionGetImplicitAllocator>(irb, scope, source_node);
3074 instruction->id = id;
3075
3076 return &instruction->base;
3077}
3078
3079static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) {
3080 IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);
3081 instruction->promise_ptr = promise_ptr;
3082
3083 ir_ref_instruction(promise_ptr, irb->current_basic_block);
3084
3085 return &instruction->base;
3086}
3087
3088static IrInstruction *ir_build_coro_alloc(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id) {
3089 IrInstructionCoroAlloc *instruction = ir_build_instruction<IrInstructionCoroAlloc>(irb, scope, source_node);
3090 instruction->coro_id = coro_id;
3091
3092 ir_ref_instruction(coro_id, irb->current_basic_block);
3093
3094 return &instruction->base;
3095}
3096
3097static IrInstruction *ir_build_coro_size(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3098 IrInstructionCoroSize *instruction = ir_build_instruction<IrInstructionCoroSize>(irb, scope, source_node);
3099
3100 return &instruction->base;
3101}
3102
3103static IrInstruction *ir_build_coro_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id, IrInstruction *coro_mem_ptr) {
3104 IrInstructionCoroBegin *instruction = ir_build_instruction<IrInstructionCoroBegin>(irb, scope, source_node);
3105 instruction->coro_id = coro_id;
3106 instruction->coro_mem_ptr = coro_mem_ptr;
3107
3108 ir_ref_instruction(coro_id, irb->current_basic_block);
3109 ir_ref_instruction(coro_mem_ptr, irb->current_basic_block);
3110
3111 return &instruction->base;
3112}
3113
3114static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_val) {
3115 IrInstructionCoroAllocFail *instruction = ir_build_instruction<IrInstructionCoroAllocFail>(irb, scope, source_node);
3116 instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
3117 instruction->base.value.special = ConstValSpecialStatic;
3118 instruction->err_val = err_val;
3119
3120 ir_ref_instruction(err_val, irb->current_basic_block);
3121
3122 return &instruction->base;
3123}
3124
3125static IrInstruction *ir_build_coro_suspend(IrBuilder *irb, Scope *scope, AstNode *source_node,
3126 IrInstruction *save_point, IrInstruction *is_final)
3127{
3128 IrInstructionCoroSuspend *instruction = ir_build_instruction<IrInstructionCoroSuspend>(irb, scope, source_node);
3129 instruction->save_point = save_point;
3130 instruction->is_final = is_final;
3131
3132 if (save_point != nullptr) ir_ref_instruction(save_point, irb->current_basic_block);
3133 ir_ref_instruction(is_final, irb->current_basic_block);
3134
3135 return &instruction->base;
3136}
3137
3138static IrInstruction *ir_build_coro_end(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3139 IrInstructionCoroEnd *instruction = ir_build_instruction<IrInstructionCoroEnd>(irb, scope, source_node);
3140 return &instruction->base;
3141}
3142
3143static IrInstruction *ir_build_coro_free(IrBuilder *irb, Scope *scope, AstNode *source_node,
3144 IrInstruction *coro_id, IrInstruction *coro_handle)
3145{
3146 IrInstructionCoroFree *instruction = ir_build_instruction<IrInstructionCoroFree>(irb, scope, source_node);
3147 instruction->coro_id = coro_id;
3148 instruction->coro_handle = coro_handle;
3149
3150 ir_ref_instruction(coro_id, irb->current_basic_block);
3151 ir_ref_instruction(coro_handle, irb->current_basic_block);
3152
3153 return &instruction->base;
3154}
3155
3156static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,
3157 IrInstruction *awaiter_handle)
3158{
3159 IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node);
3160 instruction->awaiter_handle = awaiter_handle;
3161
3162 ir_ref_instruction(awaiter_handle, irb->current_basic_block);
3163
3164 return &instruction->base;
3165}
3166
3167static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *source_node,
3168 IrInstruction *coro_handle)
3169{
3170 IrInstructionCoroSave *instruction = ir_build_instruction<IrInstructionCoroSave>(irb, scope, source_node);
3171 instruction->coro_handle = coro_handle;
3172
3173 ir_ref_instruction(coro_handle, irb->current_basic_block);
3174
3175 return &instruction->base;
3176}
3177
3178static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node,
3179 IrInstruction *coro_handle)
3180{
3181 IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node);
3182 instruction->coro_handle = coro_handle;
3183
3184 ir_ref_instruction(coro_handle, irb->current_basic_block);
3185
3186 return &instruction->base;
3187}
3188
3189static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
3190 IrInstruction *realloc_fn, IrInstruction *coro_size)
3191{
3192 IrInstructionCoroAllocHelper *instruction = ir_build_instruction<IrInstructionCoroAllocHelper>(irb, scope, source_node);
3193 instruction->realloc_fn = realloc_fn;
3194 instruction->coro_size = coro_size;
3195
3196 ir_ref_instruction(realloc_fn, irb->current_basic_block);
3197 ir_ref_instruction(coro_size, irb->current_basic_block);
3198
3199 return &instruction->base;
3200}
3201
32023030static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
32033031 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
32043032 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
......@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode
32383066 return &instruction->base;
32393067}
32403068
3241static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
3242 IrInstruction *promise_type)
3243{
3244 IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node);
3245 instruction->promise_type = promise_type;
3246
3247 ir_ref_instruction(promise_type, irb->current_basic_block);
3248
3249 return &instruction->base;
3250}
3251
3252static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, AstNode *source_node,
3253 IrInstruction *promise_result_type)
3254{
3255 IrInstructionAwaitBookkeeping *instruction = ir_build_instruction<IrInstructionAwaitBookkeeping>(irb, scope, source_node);
3256 instruction->promise_result_type = promise_result_type;
3257
3258 ir_ref_instruction(promise_result_type, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
32633069static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
32643070 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
32653071 return &instruction->base;
......@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
32763082 return &instruction->base;
32773083}
32783084
3279static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
3280 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
3281{
3282 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
3283 instruction->coro_promise_ptr = coro_promise_ptr;
3284 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
3285 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
3286
3287 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
3288 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
3289 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
3290
3291 return &instruction->base;
3292}
3293
3294static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
3295 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
3296 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
3297
3298 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
3299
3300 return &instruction->base;
3301}
3302
33033085static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
33043086 IrInstruction *container, IrInstruction *name)
33053087{
......@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode
34353217 return &instruction->base;
34363218}
34373219
3438static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3220static IrInstructionAllocaGen *ir_build_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
34393221 uint32_t align, const char *name_hint)
34403222{
34413223 IrInstructionAllocaGen *instruction = ir_create_instruction<IrInstructionAllocaGen>(&ira->new_irb,
......@@ -3459,6 +3241,87 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s
34593241 return &instruction->base;
34603242}
34613243
3244static IrInstructionSuspendBegin *ir_build_suspend_begin(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3245 IrInstructionSuspendBegin *instruction = ir_build_instruction<IrInstructionSuspendBegin>(irb, scope, source_node);
3246 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3247
3248 return instruction;
3249}
3250
3251static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstNode *source_node,
3252 IrInstructionSuspendBegin *begin)
3253{
3254 IrInstructionSuspendFinish *instruction = ir_build_instruction<IrInstructionSuspendFinish>(irb, scope, source_node);
3255 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3256 instruction->begin = begin;
3257
3258 ir_ref_instruction(&begin->base, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
3263static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
3264 IrInstruction *frame, ResultLoc *result_loc)
3265{
3266 IrInstructionAwaitSrc *instruction = ir_build_instruction<IrInstructionAwaitSrc>(irb, scope, source_node);
3267 instruction->frame = frame;
3268 instruction->result_loc = result_loc;
3269
3270 ir_ref_instruction(frame, irb->current_basic_block);
3271
3272 return &instruction->base;
3273}
3274
3275static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3276 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)
3277{
3278 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,
3279 source_instruction->scope, source_instruction->source_node);
3280 instruction->base.value.type = result_type;
3281 instruction->frame = frame;
3282 instruction->result_loc = result_loc;
3283
3284 ir_ref_instruction(frame, ira->new_irb.current_basic_block);
3285 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
3286
3287 return &instruction->base;
3288}
3289
3290static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {
3291 IrInstructionResume *instruction = ir_build_instruction<IrInstructionResume>(irb, scope, source_node);
3292 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3293 instruction->frame = frame;
3294
3295 ir_ref_instruction(frame, irb->current_basic_block);
3296
3297 return &instruction->base;
3298}
3299
3300static IrInstructionSpillBegin *ir_build_spill_begin(IrBuilder *irb, Scope *scope, AstNode *source_node,
3301 IrInstruction *operand, SpillId spill_id)
3302{
3303 IrInstructionSpillBegin *instruction = ir_build_instruction<IrInstructionSpillBegin>(irb, scope, source_node);
3304 instruction->base.value.special = ConstValSpecialStatic;
3305 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3306 instruction->operand = operand;
3307 instruction->spill_id = spill_id;
3308
3309 ir_ref_instruction(operand, irb->current_basic_block);
3310
3311 return instruction;
3312}
3313
3314static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode *source_node,
3315 IrInstructionSpillBegin *begin)
3316{
3317 IrInstructionSpillEnd *instruction = ir_build_instruction<IrInstructionSpillEnd>(irb, scope, source_node);
3318 instruction->begin = begin;
3319
3320 ir_ref_instruction(&begin->base, irb->current_basic_block);
3321
3322 return &instruction->base;
3323}
3324
34623325static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
34633326 results[ReturnKindUnconditional] = 0;
34643327 results[ReturnKindError] = 0;
......@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
34893352 continue;
34903353 case ScopeIdDeferExpr:
34913354 case ScopeIdCImport:
3492 case ScopeIdCoroPrelude:
34933355 zig_unreachable();
34943356 }
34953357 }
......@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
35453407 continue;
35463408 case ScopeIdDeferExpr:
35473409 case ScopeIdCImport:
3548 case ScopeIdCoroPrelude:
35493410 zig_unreachable();
35503411 }
35513412 }
......@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
35883449 return nullptr;
35893450}
35903451
3591static bool exec_is_async(IrExecutable *exec) {
3592 ZigFn *fn_entry = exec_fn_entry(exec);
3593 return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
3594}
3595
3596static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
3597 bool is_generated_code)
3598{
3599 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3600
3601 bool is_async = exec_is_async(irb->exec);
3602 if (!is_async) {
3603 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
3604 return_inst->is_gen = is_generated_code;
3605 return return_inst;
3606 }
3607
3608 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "Suspended");
3609 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "NotSuspended");
3610 IrBasicBlock *store_awaiter_block = ir_create_basic_block(irb, scope, "StoreAwaiter");
3611 IrBasicBlock *check_canceled_block = ir_create_basic_block(irb, scope, "CheckCanceled");
3612
3613 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
3614 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
3615 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
3616 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
3617 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
3618 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
3619 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
3620
3621 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
3622 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
3623 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
3624 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, ptr_mask, nullptr,
3625 AtomicRmwOp_or, AtomicOrderSeqCst);
3626
3627 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
3628 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
3629 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
3630
3631 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
3632 ir_build_unreachable(irb, scope, node);
3633
3634 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
3635 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
3636 // if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
3637 IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
3638 ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
3639
3640 ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
3641 IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
3642 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, await_handle);
3643 ir_build_br(irb, scope, node, irb->exec->coro_normal_final, is_comptime);
3644
3645 ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
3646 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
3647 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
3648 return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
3649}
3650
36513452static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {
36523453 assert(node->type == NodeTypeReturnExpr);
36533454
......@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
36893490 return_value = ir_build_const_void(irb, scope, node);
36903491 }
36913492
3493 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3494
36923495 size_t defer_counts[2];
36933496 ir_count_defers(irb, scope, outer_scope, defer_counts);
36943497 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3695 if (have_err_defers || irb->codegen->have_err_ret_tracing) {
3696 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3697 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
3698 if (!have_err_defers) {
3699 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3700 }
3498 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
3499 // only generate unconditional defers
3500 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3501 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3502 result_loc_ret->base.source_instruction = result;
3503 return result;
3504 }
3505 bool should_inline = ir_should_inline(irb->exec, scope);
37013506
3702 IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base,
3703 return_value);
3704 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false);
3507 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3508 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
37053509
3706 bool should_inline = ir_should_inline(irb->exec, scope);
3707 IrInstruction *is_comptime;
3708 if (should_inline) {
3709 is_comptime = ir_build_const_bool(irb, scope, node, true);
3710 } else {
3711 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3712 }
3510 if (!have_err_defers) {
3511 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3512 }
37133513
3714 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3715 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
3514 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
37163515
3717 ir_set_cursor_at_end_and_append_block(irb, err_block);
3718 if (have_err_defers) {
3719 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3720 }
3721 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3722 ir_build_save_err_ret_addr(irb, scope, node);
3723 }
3724 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3516 IrInstruction *is_comptime;
3517 if (should_inline) {
3518 is_comptime = ir_build_const_bool(irb, scope, node, should_inline);
3519 } else {
3520 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3521 }
37253522
3726 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3727 if (have_err_defers) {
3728 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3729 }
3730 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3523 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3524 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
37313525
3732 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3733 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);
3734 result_loc_ret->base.source_instruction = result;
3735 return result;
3736 } else {
3737 // generate unconditional defers
3526 ir_set_cursor_at_end_and_append_block(irb, err_block);
3527 if (have_err_defers) {
3528 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3529 }
3530 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3531 ir_build_save_err_ret_addr(irb, scope, node);
3532 }
3533 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3534
3535 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3536 if (have_err_defers) {
37383537 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3739 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);
3740 result_loc_ret->base.source_instruction = result;
3741 return result;
37423538 }
3539 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3540
3541 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3542 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3543 result_loc_ret->base.source_instruction = result;
3544 return result;
37433545 }
37443546 case ReturnKindError:
37453547 {
......@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
37473549 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
37483550 if (err_union_ptr == irb->codegen->invalid_instruction)
37493551 return irb->codegen->invalid_instruction;
3750 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true);
3552 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true, false);
37513553
37523554 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
37533555 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
......@@ -3761,19 +3563,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
37613563 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
37623564
37633565 ir_set_cursor_at_end_and_append_block(irb, return_block);
3566 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3567 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3568 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val));
3569 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3570 SpillIdRetErrCode);
3571 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3572 result_loc_ret->base.id = ResultLocIdReturn;
3573 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3574 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
37643575 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
3765 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3766 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3767
3768 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3769 result_loc_ret->base.id = ResultLocIdReturn;
3770 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3771 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
3772
37733576 if (irb->codegen->have_err_ret_tracing && !should_inline) {
37743577 ir_build_save_err_ret_addr(irb, scope, node);
37753578 }
3776 IrInstruction *ret_inst = ir_gen_async_return(irb, scope, node, err_val, false);
3579 err_val = ir_build_spill_end(irb, scope, node, spill_begin);
3580 IrInstruction *ret_inst = ir_build_return(irb, scope, node, err_val);
37773581 result_loc_ret->base.source_instruction = ret_inst;
37783582 }
37793583
......@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
39713775 incoming_values.append(else_expr_result);
39723776 }
39733777
3974 if (block_node->data.block.name != nullptr) {
3778 bool is_return_from_fn = block_node == irb->main_block_node;
3779 if (!is_return_from_fn) {
39753780 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3781 }
3782
3783 IrInstruction *result;
3784 if (block_node->data.block.name != nullptr) {
39763785 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
39773786 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
39783787 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
39793788 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3980 return ir_expr_wrap(irb, parent_scope, phi, result_loc);
3789 result = ir_expr_wrap(irb, parent_scope, phi, result_loc);
39813790 } else {
3982 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
39833791 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3984 return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
3792 result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
39853793 }
3794 if (!is_return_from_fn)
3795 return result;
3796
3797 // no need for save_err_ret_addr because this cannot return error
3798 // only generate unconditional defers
3799
3800 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result));
3801 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3802 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
39863803}
39873804
39883805static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
......@@ -4561,8 +4378,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
45614378 return irb->codegen->invalid_instruction;
45624379 }
45634380
4564 bool is_async = exec_is_async(irb->exec);
4565
45664381 switch (builtin_fn->id) {
45674382 case BuiltinFnIdInvalid:
45684383 zig_unreachable();
......@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
51855000 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);
51865001 case BuiltinFnIdFrameAddress:
51875002 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);
5188 case BuiltinFnIdHandle:
5003 case BuiltinFnIdFrameHandle:
51895004 if (!irb->exec->fn_entry) {
5190 add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
5191 return irb->codegen->invalid_instruction;
5192 }
5193 if (!is_async) {
5194 add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
5005 add_node_error(irb->codegen, node, buf_sprintf("@frame() called outside of function definition"));
51955006 return irb->codegen->invalid_instruction;
51965007 }
51975008 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);
5009 case BuiltinFnIdFrameType: {
5010 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5011 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5012 if (arg0_value == irb->codegen->invalid_instruction)
5013 return arg0_value;
5014
5015 IrInstruction *frame_type = ir_build_frame_type(irb, scope, node, arg0_value);
5016 return ir_lval_wrap(irb, scope, frame_type, lval, result_loc);
5017 }
5018 case BuiltinFnIdFrameSize: {
5019 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5020 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5021 if (arg0_value == irb->codegen->invalid_instruction)
5022 return arg0_value;
5023
5024 IrInstruction *frame_size = ir_build_frame_size_src(irb, scope, node, arg0_value);
5025 return ir_lval_wrap(irb, scope, frame_size, lval, result_loc);
5026 }
51985027 case BuiltinFnIdAlignOf:
51995028 {
52005029 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -5395,13 +5224,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
53955224 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
53965225
53975226 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5398 fn_inline, false, nullptr, nullptr, result_loc);
5227 fn_inline, false, nullptr, result_loc);
53995228 return ir_lval_wrap(irb, scope, call, lval, result_loc);
54005229 }
54015230 case BuiltinFnIdNewStackCall:
54025231 {
5403 if (node->data.fn_call_expr.params.length == 0) {
5404 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
5232 if (node->data.fn_call_expr.params.length < 2) {
5233 add_node_error(irb->codegen, node,
5234 buf_sprintf("expected at least 2 arguments, found %" ZIG_PRI_usize,
5235 node->data.fn_call_expr.params.length));
54055236 return irb->codegen->invalid_instruction;
54065237 }
54075238
......@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
54265257 }
54275258
54285259 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5429 FnInlineAuto, false, nullptr, new_stack, result_loc);
5260 FnInlineAuto, false, new_stack, result_loc);
5261 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5262 }
5263 case BuiltinFnIdAsyncCall:
5264 {
5265 size_t arg_offset = 3;
5266 if (node->data.fn_call_expr.params.length < arg_offset) {
5267 add_node_error(irb->codegen, node,
5268 buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
5269 arg_offset, node->data.fn_call_expr.params.length));
5270 return irb->codegen->invalid_instruction;
5271 }
5272
5273 AstNode *bytes_node = node->data.fn_call_expr.params.at(0);
5274 IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
5275 if (bytes == irb->codegen->invalid_instruction)
5276 return bytes;
5277
5278 AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1);
5279 IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
5280 if (ret_ptr == irb->codegen->invalid_instruction)
5281 return ret_ptr;
5282
5283 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2);
5284 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
5285 if (fn_ref == irb->codegen->invalid_instruction)
5286 return fn_ref;
5287
5288 size_t arg_count = node->data.fn_call_expr.params.length - arg_offset;
5289
5290 // last "arg" is return pointer
5291 IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
5292
5293 for (size_t i = 0; i < arg_count; i += 1) {
5294 AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset);
5295 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
5296 if (arg == irb->codegen->invalid_instruction)
5297 return arg;
5298 args[i] = arg;
5299 }
5300
5301 args[arg_count] = ret_ptr;
5302
5303 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5304 FnInlineAuto, true, bytes, result_loc);
54305305 return ir_lval_wrap(irb, scope, call, lval, result_loc);
54315306 }
54325307 case BuiltinFnIdTypeId:
......@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
57315606 }
57325607
57335608 bool is_async = node->data.fn_call_expr.is_async;
5734 IrInstruction *async_allocator = nullptr;
5735 if (is_async) {
5736 if (node->data.fn_call_expr.async_allocator) {
5737 async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
5738 if (async_allocator == irb->codegen->invalid_instruction)
5739 return async_allocator;
5740 }
5741 }
5742
5743 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
5744 is_async, async_allocator, nullptr, result_loc);
5609 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5610 FnInlineAuto, is_async, nullptr, result_loc);
57455611 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);
57465612}
57475613
......@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
62546120 LValPtr, nullptr);
62556121 if (err_val_ptr == irb->codegen->invalid_instruction)
62566122 return err_val_ptr;
6257 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, true);
6123 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr,
6124 true, false);
62586125 IrBasicBlock *after_cond_block = irb->current_basic_block;
62596126 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
62606127 IrInstruction *cond_br_inst;
......@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
67626629 }
67636630}
67646631
6765static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6766 assert(node->type == NodeTypePromiseType);
6632static IrInstruction *ir_gen_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6633 assert(node->type == NodeTypeAnyFrameType);
67676634
6768 AstNode *payload_type_node = node->data.promise_type.payload_type;
6635 AstNode *payload_type_node = node->data.anyframe_type.payload_type;
67696636 IrInstruction *payload_type_value = nullptr;
67706637
67716638 if (payload_type_node != nullptr) {
......@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
67756642
67766643 }
67776644
6778 return ir_build_promise_type(irb, scope, node, payload_type_value);
6645 return ir_build_anyframe_type(irb, scope, node, payload_type_value);
67796646}
67806647
67816648static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -7070,7 +6937,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
70706937 return err_val_ptr;
70716938
70726939 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
7073 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true);
6940 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true, false);
70746941
70756942 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
70766943 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
......@@ -7686,7 +7553,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
76867553 if (err_union_ptr == irb->codegen->invalid_instruction)
76877554 return irb->codegen->invalid_instruction;
76887555
7689 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true);
7556 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true, false);
76907557
76917558 IrInstruction *is_comptime;
76927559 if (ir_should_inline(irb->exec, parent_scope)) {
......@@ -7967,352 +7834,58 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
79677834 IrInstruction *return_type;
79687835 if (node->data.fn_proto.return_var_token == nullptr) {
79697836 if (node->data.fn_proto.return_type == nullptr) {
7970 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
7971 } else {
7972 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
7973 if (return_type == irb->codegen->invalid_instruction)
7974 return irb->codegen->invalid_instruction;
7975 }
7976 } else {
7977 add_node_error(irb->codegen, node,
7978 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
7979 return irb->codegen->invalid_instruction;
7980 //return_type = nullptr;
7981 }
7982
7983 IrInstruction *async_allocator_type_value = nullptr;
7984 if (node->data.fn_proto.async_allocator_type != nullptr) {
7985 async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
7986 if (async_allocator_type_value == irb->codegen->invalid_instruction)
7987 return irb->codegen->invalid_instruction;
7988 }
7989
7990 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type,
7991 async_allocator_type_value, is_var_args);
7992}
7993
7994static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode *node,
7995 IrInstruction *target_inst, bool cancel_non_suspended, bool cancel_awaited)
7996{
7997 IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "CancelDone");
7998 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
7999 IrBasicBlock *pre_return_block = ir_create_basic_block(irb, scope, "PreReturn");
8000 IrBasicBlock *post_return_block = ir_create_basic_block(irb, scope, "PostReturn");
8001 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
8002
8003 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8004 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8005 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
8006 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8007 IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node,
8008 get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
8009 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
8010 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8011 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
8012 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8013
8014 // TODO relies on Zig not re-ordering fields
8015 IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst,
8016 false);
8017 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
8018 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8019 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8020 atomic_state_field_name, false);
8021
8022 // set the is_canceled bit
8023 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8024 usize_type_val, atomic_state_ptr, nullptr, is_canceled_mask, nullptr,
8025 AtomicRmwOp_or, AtomicOrderSeqCst);
8026
8027 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8028 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8029 ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
8030
8031 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8032 IrInstruction *awaiter_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8033 IrInstruction *is_returned_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, awaiter_addr, ptr_mask, false);
8034 ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime);
8035
8036 ir_set_cursor_at_end_and_append_block(irb, post_return_block);
8037 if (cancel_awaited) {
8038 ir_build_br(irb, scope, node, do_cancel_block, is_comptime);
8039 } else {
8040 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
8041 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
8042 ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime);
8043 }
8044
8045 ir_set_cursor_at_end_and_append_block(irb, pre_return_block);
8046 if (cancel_awaited) {
8047 if (cancel_non_suspended) {
8048 ir_build_br(irb, scope, node, do_cancel_block, is_comptime);
8049 } else {
8050 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8051 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8052 ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime);
8053 }
8054 } else {
8055 ir_build_br(irb, scope, node, done_block, is_comptime);
8056 }
8057
8058 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
8059 ir_build_cancel(irb, scope, node, target_inst);
8060 ir_build_br(irb, scope, node, done_block, is_comptime);
8061
8062 ir_set_cursor_at_end_and_append_block(irb, done_block);
8063 return ir_build_const_void(irb, scope, node);
8064}
8065
8066static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {
8067 assert(node->type == NodeTypeCancel);
8068
8069 IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope);
8070 if (target_inst == irb->codegen->invalid_instruction)
7837 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
7838 } else {
7839 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
7840 if (return_type == irb->codegen->invalid_instruction)
7841 return irb->codegen->invalid_instruction;
7842 }
7843 } else {
7844 add_node_error(irb->codegen, node,
7845 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
80717846 return irb->codegen->invalid_instruction;
7847 //return_type = nullptr;
7848 }
80727849
8073 return ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
8074}
8075
8076static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode *node,
8077 IrInstruction *target_inst)
8078{
8079 IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "ResumeDone");
8080 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
8081 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "IsSuspended");
8082 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "IsNotSuspended");
8083
8084 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8085 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8086 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8087 IrInstruction *and_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, is_suspended_mask);
8088 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
8089 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8090 IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node,
8091 get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
8092
8093 // TODO relies on Zig not re-ordering fields
8094 IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst,
8095 false);
8096 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
8097 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8098 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8099 atomic_state_field_name, false);
8100
8101 // clear the is_suspended bit
8102 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8103 usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr,
8104 AtomicRmwOp_and, AtomicOrderSeqCst);
8105
8106 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8107 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8108 ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
8109
8110 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8111 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8112 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8113 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
8114
8115 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
8116 ir_build_unreachable(irb, scope, node);
8117
8118 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
8119 ir_build_coro_resume(irb, scope, node, target_inst);
8120 ir_build_br(irb, scope, node, done_block, is_comptime);
8121
8122 ir_set_cursor_at_end_and_append_block(irb, done_block);
8123 return ir_build_const_void(irb, scope, node);
7850 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
81247851}
81257852
81267853static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
81277854 assert(node->type == NodeTypeResume);
81287855
8129 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);
7856 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr);
81307857 if (target_inst == irb->codegen->invalid_instruction)
81317858 return irb->codegen->invalid_instruction;
81327859
8133 return ir_gen_resume_target(irb, scope, node, target_inst);
7860 return ir_build_resume(irb, scope, node, target_inst);
81347861}
81357862
8136static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
7863static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
7864 ResultLoc *result_loc)
7865{
81377866 assert(node->type == NodeTypeAwaitExpr);
81387867
8139 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
8140 if (target_inst == irb->codegen->invalid_instruction)
8141 return irb->codegen->invalid_instruction;
8142
81437868 ZigFn *fn_entry = exec_fn_entry(irb->exec);
81447869 if (!fn_entry) {
81457870 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
81467871 return irb->codegen->invalid_instruction;
81477872 }
8148 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
8149 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));
8150 return irb->codegen->invalid_instruction;
8151 }
8152
8153 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);
8154 if (scope_defer_expr) {
8155 if (!scope_defer_expr->reported_err) {
8156 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
8157 scope_defer_expr->reported_err = true;
7873 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
7874 if (existing_suspend_scope) {
7875 if (!existing_suspend_scope->reported_err) {
7876 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block"));
7877 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
7878 existing_suspend_scope->reported_err = true;
81587879 }
81597880 return irb->codegen->invalid_instruction;
81607881 }
81617882
8162 Scope *outer_scope = irb->exec->begin_scope;
7883 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr);
7884 if (target_inst == irb->codegen->invalid_instruction)
7885 return irb->codegen->invalid_instruction;
81637886
8164 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);
8165 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
8166 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8167
8168 if (irb->codegen->have_err_ret_tracing) {
8169 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8170 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8171 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8172 ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
8173 }
8174
8175 IrBasicBlock *already_awaited_block = ir_create_basic_block(irb, scope, "AlreadyAwaited");
8176 IrBasicBlock *not_awaited_block = ir_create_basic_block(irb, scope, "NotAwaited");
8177 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
8178 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, scope, "YesSuspend");
8179 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, scope, "NoSuspend");
8180 IrBasicBlock *merge_block = ir_create_basic_block(irb, scope, "MergeSuspend");
8181 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, scope, "SuspendCleanup");
8182 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "SuspendResume");
8183 IrBasicBlock *cancel_target_block = ir_create_basic_block(irb, scope, "CancelTarget");
8184 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
8185 IrBasicBlock *do_defers_block = ir_create_basic_block(irb, scope, "DoDefers");
8186 IrBasicBlock *destroy_block = ir_create_basic_block(irb, scope, "DestroyBlock");
8187 IrBasicBlock *my_suspended_block = ir_create_basic_block(irb, scope, "AlreadySuspended");
8188 IrBasicBlock *my_not_suspended_block = ir_create_basic_block(irb, scope, "NotAlreadySuspended");
8189 IrBasicBlock *do_suspend_block = ir_create_basic_block(irb, scope, "DoSuspend");
8190
8191 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8192 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8193 atomic_state_field_name, false);
8194
8195 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
8196 IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
8197 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
8198 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8199 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8200 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
8201 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8202 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
8203 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8204 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8205
8206 ZigVar *result_var = ir_create_var(irb, node, scope, nullptr,
8207 false, false, true, const_bool_false);
8208 IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
8209 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
8210 ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
8211 IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef, nullptr);
8212 build_decl_var_and_init(irb, scope, node, result_var, undef_promise_result, "result", const_bool_false);
8213 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
8214 ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
8215 IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
8216
8217 IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
8218 IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false);
8219 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8220 usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr,
8221 AtomicRmwOp_or, AtomicOrderSeqCst);
8222
8223 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
8224 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
8225 ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
8226
8227 ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
8228 ir_build_unreachable(irb, scope, node);
8229
8230 ir_set_cursor_at_end_and_append_block(irb, not_awaited_block);
8231 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8232 IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8233 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8234 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8235 ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
8236
8237 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8238 ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
8239
8240 ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
8241 ir_build_cancel(irb, scope, node, target_inst);
8242 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8243
8244 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
8245 if (irb->codegen->have_err_ret_tracing) {
8246 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8247 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8248 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8249 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
8250 }
8251 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8252 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8253 // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
8254 // because we're about to destroy the memory. So we store it into our result variable.
8255 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
8256 ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
8257 ir_build_cancel(irb, scope, node, target_inst);
8258 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8259
8260
8261 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
8262 IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8263 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8264 AtomicRmwOp_or, AtomicOrderSeqCst);
8265 IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
8266 IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
8267 ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
8268
8269 ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
8270 ir_build_unreachable(irb, scope, node);
8271
8272 ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
8273 IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
8274 IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
8275 ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
8276
8277 ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
8278 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
8279
8280 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8281 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8282 cases[0].block = resume_block;
8283 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8284 cases[1].block = destroy_block;
8285 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
8286 2, cases, const_bool_false, nullptr);
8287
8288 ir_set_cursor_at_end_and_append_block(irb, destroy_block);
8289 ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
8290 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8291
8292 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8293 IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false);
8294 IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8295 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr,
8296 AtomicRmwOp_or, AtomicOrderSeqCst);
8297 IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
8298 IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
8299 IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
8300 ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
8301
8302 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
8303 IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
8304 ir_gen_cancel_target(irb, scope, node, my_await_handle, true, false);
8305 ir_mark_gen(ir_build_br(irb, scope, node, do_defers_block, const_bool_false));
8306
8307 ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
8308 ir_gen_defers_for_block(irb, scope, outer_scope, true);
8309 ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
8310
8311 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8312 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8313
8314 ir_set_cursor_at_end_and_append_block(irb, merge_block);
8315 return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
7887 IrInstruction *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc);
7888 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
83167889}
83177890
83187891static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
......@@ -8323,20 +7896,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
83237896 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
83247897 return irb->codegen->invalid_instruction;
83257898 }
8326 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
8327 add_node_error(irb->codegen, node, buf_sprintf("suspend in non-async function"));
8328 return irb->codegen->invalid_instruction;
8329 }
8330
8331 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
8332 if (scope_defer_expr) {
8333 if (!scope_defer_expr->reported_err) {
8334 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
8335 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
8336 scope_defer_expr->reported_err = true;
8337 }
8338 return irb->codegen->invalid_instruction;
8339 }
83407899 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
83417900 if (existing_suspend_scope) {
83427901 if (!existing_suspend_scope->reported_err) {
......@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
83477906 return irb->codegen->invalid_instruction;
83487907 }
83497908
8350 Scope *outer_scope = irb->exec->begin_scope;
8351
8352 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
8353 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
8354 IrBasicBlock *suspended_block = ir_create_basic_block(irb, parent_scope, "AlreadySuspended");
8355 IrBasicBlock *canceled_block = ir_create_basic_block(irb, parent_scope, "IsCanceled");
8356 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, parent_scope, "NotCanceled");
8357 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, parent_scope, "NotAlreadySuspended");
8358 IrBasicBlock *cancel_awaiter_block = ir_create_basic_block(irb, parent_scope, "CancelAwaiter");
8359
8360 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_promise);
8361 IrInstruction *const_bool_true = ir_build_const_bool(irb, parent_scope, node, true);
8362 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
8363 IrInstruction *usize_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_usize);
8364 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, parent_scope, node, 0x1); // 0b001
8365 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, parent_scope, node, 0x2); // 0b010
8366 IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0);
8367 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, parent_scope, node, 0x7); // 0b111
8368 IrInstruction *ptr_mask = ir_build_un_op(irb, parent_scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8369
8370 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, parent_scope, node,
8371 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8372 AtomicRmwOp_or, AtomicOrderSeqCst);
8373
8374 IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8375 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8376 ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
8377
8378 ir_set_cursor_at_end_and_append_block(irb, canceled_block);
8379 IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8380 IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8381 IrBasicBlock *post_canceled_block = irb->current_basic_block;
8382 ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
8383
8384 ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
8385 IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
8386 ir_gen_cancel_target(irb, parent_scope, node, await_handle, true, false);
8387 IrBasicBlock *post_cancel_awaiter_block = irb->current_basic_block;
8388 ir_build_br(irb, parent_scope, node, cleanup_block, const_bool_false);
8389
8390 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8391 IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8392 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8393 ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
8394
8395 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
8396 ir_build_unreachable(irb, parent_scope, node);
8397
8398 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
8399 IrInstruction *suspend_code;
8400 if (node->data.suspend.block == nullptr) {
8401 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false);
8402 } else {
8403 Scope *child_scope;
7909 IrInstructionSuspendBegin *begin = ir_build_suspend_begin(irb, parent_scope, node);
7910 if (node->data.suspend.block != nullptr) {
84047911 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
8405 suspend_scope->resume_block = resume_block;
8406 child_scope = &suspend_scope->base;
8407 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
8408 ir_gen_node(irb, node->data.suspend.block, child_scope);
8409 suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
8410 }
8411
8412 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8413 cases[0].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 0));
8414 cases[0].block = resume_block;
8415 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
8416 cases[1].block = canceled_block;
8417 IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, parent_scope, node, suspend_code,
8418 irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8419 ir_mark_gen(&switch_br->base);
8420
8421 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8422 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8423 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8424 incoming_blocks[0] = post_canceled_block;
8425 incoming_values[0] = const_bool_true;
8426 incoming_blocks[1] = post_cancel_awaiter_block;
8427 incoming_values[1] = const_bool_false;
8428 IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values,
8429 nullptr);
8430 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
8431 ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
7912 Scope *child_scope = &suspend_scope->base;
7913 IrInstruction *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
7914 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
7915 }
84327916
8433 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8434 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
7917 return ir_build_suspend_finish(irb, parent_scope, node, begin);
84357918}
84367919
84377920static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
......@@ -8523,8 +8006,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
85238006 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);
85248007 case NodeTypePointerType:
85258008 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);
8526 case NodeTypePromiseType:
8527 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc);
8009 case NodeTypeAnyFrameType:
8010 return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc);
85288011 case NodeTypeStringLiteral:
85298012 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);
85308013 case NodeTypeUndefinedLiteral:
......@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
85618044 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);
85628045 case NodeTypeErrorSetDecl:
85638046 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc);
8564 case NodeTypeCancel:
8565 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc);
85668047 case NodeTypeResume:
85678048 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);
85688049 case NodeTypeAwaitExpr:
8569 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval, result_loc);
8050 return ir_gen_await_expr(irb, scope, node, lval, result_loc);
85708051 case NodeTypeSuspend:
85718052 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);
85728053 case NodeTypeEnumLiteral:
......@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
86268107
86278108 irb->codegen = codegen;
86288109 irb->exec = ir_executable;
8110 irb->main_block_node = node;
86298111
86308112 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");
86318113 ir_set_cursor_at_end_and_append_block(irb, entry_block);
86328114 // Entry block gets a reference because we enter it to begin.
86338115 ir_ref_bb(irb->current_basic_block);
86348116
8635 ZigFn *fn_entry = exec_fn_entry(irb->exec);
8636
8637 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
8638 IrInstruction *coro_id;
8639 IrInstruction *u8_ptr_type;
8640 IrInstruction *const_bool_false;
8641 IrInstruction *coro_promise_ptr;
8642 IrInstruction *err_ret_trace_ptr;
8643 ZigType *return_type;
8644 Buf *result_ptr_field_name;
8645 ZigVar *coro_size_var;
8646 if (is_async) {
8647 // create the coro promise
8648 Scope *coro_scope = create_coro_prelude_scope(irb->codegen, node, scope);
8649 const_bool_false = ir_build_const_bool(irb, coro_scope, node, false);
8650 ZigVar *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8651
8652 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
8653 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
8654 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
8655 ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
8656 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
8657 IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef, nullptr);
8658 build_decl_var_and_init(irb, coro_scope, node, promise_var, undef_coro_frame, "promise", const_bool_false);
8659 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
8660
8661 ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8662 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
8663 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
8664 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
8665 IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value, nullptr);
8666 build_decl_var_and_init(irb, coro_scope, node, await_handle_var, null_await_handle, "await_handle", const_bool_false);
8667 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
8668
8669 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
8670 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
8671 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type,
8672 coro_promise_ptr, false);
8673 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
8674 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8675 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
8676 build_decl_var_and_init(irb, coro_scope, node, coro_size_var, coro_size, "coro_size", const_bool_false);
8677 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
8678 ImplicitAllocatorIdArg);
8679 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
8680 build_decl_var_and_init(irb, coro_scope, node, irb->exec->coro_allocator_var, implicit_allocator_ptr,
8681 "allocator", const_bool_false);
8682 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);
8683 IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name, false);
8684 IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr);
8685 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, realloc_fn, coro_size);
8686 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
8687 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
8688 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
8689 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
8690
8691 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
8692 // we can return undefined here, because the caller passes a pointer to the error struct field
8693 // in the error union result, and we populate it in case of allocation failure.
8694 ir_build_return(irb, coro_scope, node, undef);
8695
8696 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
8697 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr,
8698 false);
8699 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
8700
8701 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8702 irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8703 atomic_state_field_name, false);
8704 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8705 ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
8706 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8707 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8708 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
8709 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8710 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
8711 if (irb->codegen->have_err_ret_tracing) {
8712 // initialize the error return trace
8713 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
8714 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name, false);
8715
8716 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8717 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8718 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
8719
8720 // coordinate with builtin.zig
8721 Buf *index_name = buf_create_from_str("index");
8722 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name, false);
8723 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
8724
8725 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
8726 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false);
8727
8728 IrInstruction *slice_value = ir_build_slice_src(irb, scope, node, return_addresses_ptr, zero, nullptr, false, no_result_loc());
8729 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
8730 }
8731
8732
8733 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
8734 irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal");
8735 irb->exec->coro_suspend_block = ir_create_basic_block(irb, scope, "Suspend");
8736 irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
8737 }
8738
87398117 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
87408118 assert(result);
87418119 if (irb->exec->invalid)
87428120 return false;
87438121
87448122 if (!instr_is_unreachable(result)) {
8123 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));
87458124 // no need for save_err_ret_addr because this cannot return error
8746 ir_gen_async_return(irb, scope, result->source_node, result, true);
8747 }
8748
8749 if (is_async) {
8750 IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume");
8751 IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree");
8752
8753 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final);
8754 IrInstruction *const_bool_true = ir_build_const_bool(irb, scope, node, true);
8755 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, nullptr, const_bool_true);
8756 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8757 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8758 cases[0].block = invalid_resume_block;
8759 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8760 cases[1].block = irb->exec->coro_final_cleanup_block;
8761 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8762
8763 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
8764 ir_build_coro_end(irb, scope, node);
8765 ir_build_return(irb, scope, node, irb->exec->coro_handle);
8766
8767 ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block);
8768 ir_build_unreachable(irb, scope, node);
8769
8770 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
8771 if (type_has_bits(return_type)) {
8772 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8773 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8774 false, false, PtrLenUnknown, 0, 0, 0, false));
8775 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
8776 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8777 result_ptr, false);
8778 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node,
8779 u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false);
8780 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
8781 fn_entry->type_entry->data.fn.fn_type_id.return_type);
8782 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
8783 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
8784 }
8785 if (irb->codegen->have_err_ret_tracing) {
8786 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8787 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8788 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
8789 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
8790 }
8791 // Before we destroy the coroutine frame, we need to load the target promise into
8792 // a register or local variable which does not get spilled into the frame,
8793 // otherwise llvm tries to access memory inside the destroyed frame.
8794 IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
8795 irb->exec->await_handle_var_ptr, false, false);
8796 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
8797 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8798
8799 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
8800 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8801
8802 ir_set_cursor_at_end_and_append_block(irb, check_free_block);
8803 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8804 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8805 incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8806 incoming_values[0] = const_bool_false;
8807 incoming_blocks[1] = irb->exec->coro_normal_final;
8808 incoming_values[1] = const_bool_true;
8809 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr);
8810
8811 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
8812 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
8813 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8814 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
8815 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
8816 merge_incoming_values[1] = await_handle_in_block;
8817 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values, nullptr);
8818
8819 Buf *shrink_field_name = buf_create_from_str(ASYNC_SHRINK_FIELD_NAME);
8820 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
8821 ImplicitAllocatorIdLocalVar);
8822 IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name, false);
8823 IrInstruction *shrink_fn = ir_build_load_ptr(irb, scope, node, shrink_fn_ptr);
8824 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8825 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
8826 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8827 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8828 false, false, PtrLenUnknown, 0, 0, 0, false));
8829 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8830 coro_mem_ptr_maybe, false);
8831 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
8832 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
8833 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
8834 IrInstruction *mem_slice = ir_build_slice_src(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
8835 no_result_loc());
8836 size_t arg_count = 5;
8837 IrInstruction **args = allocate<IrInstruction *>(arg_count);
8838 args[0] = implicit_allocator_ptr; // self
8839 args[1] = mem_slice; // old_mem
8840 args[2] = ir_build_const_usize(irb, scope, node, 8); // old_align
8841 // TODO: intentional memory leak here. If this is set to 0 then there is an issue where a coroutine
8842 // calls the function and it frees its own stack frame, but then the return value is a slice, which
8843 // is implemented as an sret struct. writing to the return pointer causes invalid memory write.
8844 // We could work around it by having a global helper function which has a void return type
8845 // and calling that instead. But instead this hack will suffice until I rework coroutines to be
8846 // non-allocating. Basically coroutines are not supported right now until they are reworked.
8847 args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size
8848 args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align
8849 ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr,
8850 nullptr, no_result_loc());
8851
8852 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
8853 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
8854
8855 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8856 ir_gen_resume_target(irb, scope, node, awaiter_handle);
8857 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
8125 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
88588126 }
88598127
88608128 return true;
......@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
88718139 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);
88728140}
88738141
8874static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
8142static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
88758143 if (!exec || !exec->source_node || limit < 0) return;
88768144 add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));
88778145
8878 add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
8146 ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
8147}
8148
8149void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) {
8150 IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
8151 add_error_note(ira->codegen, err_msg, old_instruction->source_node, text);
8152 ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10);
88798153}
88808154
88818155static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
88828156 invalidate_exec(exec);
88838157 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
88848158 if (exec->parent_exec) {
8885 add_call_stack_errors(codegen, exec, err_msg, 10);
8159 ir_add_call_stack_errors(codegen, exec, err_msg, 10);
88868160 }
88878161 return err_msg;
88888162}
......@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec
89468220 IrInstruction *instruction = bb->instruction_list.at(i);
89478221 if (instruction->id == IrInstructionIdReturn) {
89488222 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;
8949 IrInstruction *value = ret_inst->value;
8950 if (value->value.special == ConstValSpecialRuntime) {
8951 exec_add_error_node(codegen, exec, value->source_node,
8223 IrInstruction *operand = ret_inst->operand;
8224 if (operand->value.special == ConstValSpecialRuntime) {
8225 exec_add_error_node(codegen, exec, operand->source_node,
89528226 buf_sprintf("unable to evaluate constant expression"));
89538227 return &codegen->invalid_instruction->value;
89548228 }
8955 return &value->value;
8229 return &operand->value;
89568230 } else if (ir_has_side_effects(instruction)) {
89578231 if (instr_is_comptime(instruction)) {
89588232 switch (instruction->id) {
......@@ -10203,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
102039477 return result;
102049478 }
102059479
10206 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
10207 actual_type->id == ZigTypeIdPromise)
10208 {
10209 return result;
10210 }
10211
102129480 // fn
102139481 if (wanted_type->id == ZigTypeIdFn &&
102149482 actual_type->id == ZigTypeIdFn)
......@@ -10243,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
102439511 return result;
102449512 }
102459513 }
10246 if (!wanted_type->data.fn.is_generic && wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
10247 ConstCastOnly child = types_match_const_cast_only(ira,
10248 actual_type->data.fn.fn_type_id.async_allocator_type,
10249 wanted_type->data.fn.fn_type_id.async_allocator_type,
10250 source_node, false);
10251 if (child.id == ConstCastResultIdInvalid)
10252 return child;
10253 if (child.id != ConstCastResultIdOk) {
10254 result.id = ConstCastResultIdAsyncAllocatorType;
10255 result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
10256 *result.data.async_allocator_type = child;
10257 return result;
10258 }
10259 }
102609514 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
102619515 result.id = ConstCastResultIdFnArgCount;
102629516 return result;
......@@ -10561,6 +9815,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
105619815
105629816 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
105639817 ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type;
9818 if (prev_err_set_type == cur_err_set_type)
9819 continue;
105649820
105659821 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
105669822 return ira->codegen->builtin_types.entry_invalid;
......@@ -11206,7 +10462,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,
1120610462}
1120710463
1120810464static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) {
11209 ir_assert(!old_bb->suspended, old_bb->instruction_list.at(0));
10465 ir_assert(!old_bb->suspended, (old_bb->instruction_list.length != 0) ? old_bb->instruction_list.at(0) : nullptr);
1121010466 ira->instruction_index = 0;
1121110467 ira->old_irb.current_basic_block = old_bb;
1121210468 ira->const_predecessor_bb = const_predecessor_bb;
......@@ -11729,6 +10985,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
1172910985 return result;
1173010986}
1173110987
10988static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr,
10989 IrInstruction *value, ZigType *wanted_type)
10990{
10991 if (instr_is_comptime(value)) {
10992 zig_panic("TODO comptime frame pointer");
10993 }
10994
10995 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
10996 wanted_type, value, CastOpBitCast);
10997 result->value.type = wanted_type;
10998 return result;
10999}
11000
11001static IrInstruction *ir_analyze_anyframe_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr,
11002 IrInstruction *value, ZigType *wanted_type)
11003{
11004 if (instr_is_comptime(value)) {
11005 zig_panic("TODO comptime anyframe->T to anyframe");
11006 }
11007
11008 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
11009 wanted_type, value, CastOpBitCast);
11010 result->value.type = wanted_type;
11011 return result;
11012}
11013
11014
1173211015static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
1173311016 ZigType *wanted_type, ResultLoc *result_loc)
1173411017{
......@@ -12576,12 +11859,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou
1257611859static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {
1257711860 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;
1257811861 if (ty->id == ZigTypeIdFn) return true;
12579 if (ty->id == ZigTypeIdPromise) return true;
1258011862 if (ty->id == ZigTypeIdOptional) {
1258111863 ZigType *ptr_ty = ty->data.maybe.child_type;
1258211864 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;
1258311865 if (ptr_ty->id == ZigTypeIdFn) return true;
12584 if (ptr_ty->id == ZigTypeIdPromise) return true;
1258511866 }
1258611867 return false;
1258711868}
......@@ -12829,6 +12110,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1282912110 }
1283012111 }
1283112112
12113 // *@Frame(func) to anyframe->T or anyframe
12114 if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle &&
12115 actual_type->data.pointer.child_type->id == ZigTypeIdFnFrame && wanted_type->id == ZigTypeIdAnyFrame)
12116 {
12117 bool ok = true;
12118 if (wanted_type->data.any_frame.result_type != nullptr) {
12119 ZigFn *fn = actual_type->data.pointer.child_type->data.frame.fn;
12120 ZigType *fn_return_type = fn->type_entry->data.fn.fn_type_id.return_type;
12121 if (wanted_type->data.any_frame.result_type != fn_return_type) {
12122 ok = false;
12123 }
12124 }
12125 if (ok) {
12126 return ir_analyze_frame_ptr_to_anyframe(ira, source_instr, value, wanted_type);
12127 }
12128 }
12129
12130 // anyframe->T to anyframe
12131 if (actual_type->id == ZigTypeIdAnyFrame && actual_type->data.any_frame.result_type != nullptr &&
12132 wanted_type->id == ZigTypeIdAnyFrame && wanted_type->data.any_frame.result_type == nullptr)
12133 {
12134 return ir_analyze_anyframe_to_anyframe(ira, source_instr, value, wanted_type);
12135 }
1283212136
1283312137 // cast from null literal to maybe type
1283412138 if (wanted_type->id == ZigTypeIdOptional &&
......@@ -13333,11 +12637,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
1333312637}
1333412638
1333512639static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {
13336 IrInstruction *value = instruction->value->child;
13337 if (type_is_invalid(value->value.type))
12640 IrInstruction *operand = instruction->operand->child;
12641 if (type_is_invalid(operand->value.type))
1333812642 return ir_unreach_error(ira);
1333912643
13340 if (!instr_is_comptime(value) && handle_is_ptr(ira->explicit_return_type)) {
12644 if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) {
1334112645 // result location mechanism took care of it.
1334212646 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
1334312647 instruction->base.source_node, nullptr);
......@@ -13345,8 +12649,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
1334512649 return ir_finish_anal(ira, result);
1334612650 }
1334712651
13348 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
13349 if (type_is_invalid(casted_value->value.type)) {
12652 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type);
12653 if (type_is_invalid(casted_operand->value.type)) {
1335012654 AstNode *source_node = ira->explicit_return_type_source_node;
1335112655 if (source_node != nullptr) {
1335212656 ErrorMsg *msg = ira->codegen->errors.last();
......@@ -13356,15 +12660,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
1335612660 return ir_unreach_error(ira);
1335712661 }
1335812662
13359 if (casted_value->value.special == ConstValSpecialRuntime &&
13360 casted_value->value.type->id == ZigTypeIdPointer &&
13361 casted_value->value.data.rh_ptr == RuntimeHintPtrStack)
12663 if (casted_operand->value.special == ConstValSpecialRuntime &&
12664 casted_operand->value.type->id == ZigTypeIdPointer &&
12665 casted_operand->value.data.rh_ptr == RuntimeHintPtrStack)
1336212666 {
13363 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
12667 ir_add_error(ira, casted_operand, buf_sprintf("function returns address of local variable"));
1336412668 return ir_unreach_error(ira);
1336512669 }
12670
1336612671 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
13367 instruction->base.source_node, casted_value);
12672 instruction->base.source_node, casted_operand);
1336812673 result->value.type = ira->codegen->builtin_types.entry_unreachable;
1336912674 return ir_finish_anal(ira, result);
1337012675}
......@@ -13658,9 +12963,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1365812963 case ZigTypeIdOpaque:
1365912964 case ZigTypeIdBoundFn:
1366012965 case ZigTypeIdArgTuple:
13661 case ZigTypeIdPromise:
1366212966 case ZigTypeIdEnum:
1366312967 case ZigTypeIdEnumLiteral:
12968 case ZigTypeIdAnyFrame:
1366412969 operator_allowed = is_equality_cmp;
1366512970 break;
1366612971
......@@ -13675,6 +12980,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1367512980 case ZigTypeIdNull:
1367612981 case ZigTypeIdErrorUnion:
1367712982 case ZigTypeIdUnion:
12983 case ZigTypeIdFnFrame:
1367812984 operator_allowed = false;
1367912985 break;
1368012986 case ZigTypeIdOptional:
......@@ -15039,7 +14345,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1503914345 case ZigTypeIdBoundFn:
1504014346 case ZigTypeIdArgTuple:
1504114347 case ZigTypeIdOpaque:
15042 case ZigTypeIdPromise:
14348 case ZigTypeIdFnFrame:
14349 case ZigTypeIdAnyFrame:
1504314350 ir_add_error(ira, target,
1504414351 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));
1504514352 break;
......@@ -15063,8 +14370,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1506314370 case ZigTypeIdBoundFn:
1506414371 case ZigTypeIdArgTuple:
1506514372 case ZigTypeIdOpaque:
15066 case ZigTypeIdPromise:
1506714373 case ZigTypeIdEnumLiteral:
14374 case ZigTypeIdFnFrame:
14375 case ZigTypeIdAnyFrame:
1506814376 ir_add_error(ira, target,
1506914377 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));
1507014378 break;
......@@ -15091,8 +14399,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
1509114399static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1509214400 IrInstructionErrorReturnTrace *instruction)
1509314401{
14402 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false);
1509414403 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
15095 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
1509614404 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
1509714405 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
1509814406 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);
......@@ -15110,7 +14418,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1511014418 assert(ira->codegen->have_err_ret_tracing);
1511114419 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
1511214420 instruction->base.source_node, instruction->optional);
15113 new_instruction->value.type = get_ptr_to_stack_trace_type(ira->codegen);
14421 new_instruction->value.type = ptr_to_stack_trace_type;
1511414422 return new_instruction;
1511514423 }
1511614424}
......@@ -15142,42 +14450,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
1514214450 return ir_const_type(ira, &instruction->base, result_type);
1514314451}
1514414452
15145IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_instr, ImplicitAllocatorId id) {
15146 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
15147 if (parent_fn_entry == nullptr) {
15148 ir_add_error(ira, source_instr, buf_sprintf("no implicit allocator available"));
15149 return ira->codegen->invalid_instruction;
15150 }
15151
15152 FnTypeId *parent_fn_type = &parent_fn_entry->type_entry->data.fn.fn_type_id;
15153 if (parent_fn_type->cc != CallingConventionAsync) {
15154 ir_add_error(ira, source_instr, buf_sprintf("async function call from non-async caller requires allocator parameter"));
15155 return ira->codegen->invalid_instruction;
15156 }
15157
15158 assert(parent_fn_type->async_allocator_type != nullptr);
15159
15160 switch (id) {
15161 case ImplicitAllocatorIdArg:
15162 {
15163 IrInstruction *result = ir_build_get_implicit_allocator(&ira->new_irb, source_instr->scope,
15164 source_instr->source_node, ImplicitAllocatorIdArg);
15165 result->value.type = parent_fn_type->async_allocator_type;
15166 return result;
15167 }
15168 case ImplicitAllocatorIdLocalVar:
15169 {
15170 ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
15171 assert(coro_allocator_var != nullptr);
15172 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var);
15173 IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr);
15174 assert(result->value.type != nullptr);
15175 return result;
15176 }
15177 }
15178 zig_unreachable();
15179}
15180
1518114453static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,
1518214454 uint32_t align, const char *name_hint, bool force_comptime)
1518314455{
......@@ -15186,7 +14458,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in
1518614458 ConstExprValue *pointee = create_const_vals(1);
1518714459 pointee->special = ConstValSpecialUndef;
1518814460
15189 IrInstructionAllocaGen *result = ir_create_alloca_gen(ira, source_inst, align, name_hint);
14461 IrInstructionAllocaGen *result = ir_build_alloca_gen(ira, source_inst, align, name_hint);
1519014462 result->base.value.special = ConstValSpecialStatic;
1519114463 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
1519214464 result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer;
......@@ -15283,7 +14555,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1528314555 return nullptr;
1528414556 }
1528514557 // need to return a result location and don't have one. use a stack allocation
15286 IrInstructionAllocaGen *alloca_gen = ir_create_alloca_gen(ira, suspend_source_instr, 0, "");
14558 IrInstructionAllocaGen *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr, 0, "");
1528714559 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))
1528814560 return ira->codegen->invalid_instruction;
1528914561 alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false,
......@@ -15353,8 +14625,12 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1535314625 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {
1535414626 return ira->codegen->invalid_instruction;
1535514627 }
15356 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type))
15357 return nullptr;
14628 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) {
14629 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
14630 if (fn_entry == nullptr || fn_entry->inferred_async_node == nullptr) {
14631 return nullptr;
14632 }
14633 }
1535814634
1535914635 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);
1536014636 result_loc->written = true;
......@@ -15616,48 +14892,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
1561614892
1561714893static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
1561814894 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
15619 IrInstruction *async_allocator_inst)
14895 IrInstruction *casted_new_stack)
1562014896{
15621 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);
15622 ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base);
15623 ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type;
15624 IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, realloc_field_name, &call_instruction->base,
15625 async_allocator_inst, container_type, false);
15626 if (type_is_invalid(field_ptr_inst->value.type)) {
15627 return ira->codegen->invalid_instruction;
15628 }
15629 ZigType *ptr_to_realloc_fn_type = field_ptr_inst->value.type;
15630 ir_assert(ptr_to_realloc_fn_type->id == ZigTypeIdPointer, &call_instruction->base);
14897 if (casted_new_stack != nullptr) {
14898 // this is an @asyncCall
1563114899
15632 ZigType *realloc_fn_type = ptr_to_realloc_fn_type->data.pointer.child_type;
15633 if (realloc_fn_type->id != ZigTypeIdFn) {
15634 ir_add_error(ira, &call_instruction->base,
15635 buf_sprintf("expected reallocation function, found '%s'", buf_ptr(&realloc_fn_type->name)));
15636 return ira->codegen->invalid_instruction;
15637 }
14900 if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
14901 ir_add_error(ira, fn_ref,
14902 buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
14903 return ira->codegen->invalid_instruction;
14904 }
14905
14906 IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child;
14907 if (type_is_invalid(ret_ptr->value.type))
14908 return ira->codegen->invalid_instruction;
14909
14910 ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type);
1563814911
15639 ZigType *realloc_fn_return_type = realloc_fn_type->data.fn.fn_type_id.return_type;
15640 if (realloc_fn_return_type->id != ZigTypeIdErrorUnion) {
15641 ir_add_error(ira, fn_ref,
15642 buf_sprintf("expected allocation function to return error union, but it returns '%s'", buf_ptr(&realloc_fn_return_type->name)));
14912 IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
14913 arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type);
14914 return &call_gen->base;
14915 } else if (fn_entry == nullptr) {
14916 ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
1564314917 return ira->codegen->invalid_instruction;
1564414918 }
15645 ZigType *alloc_fn_error_set_type = realloc_fn_return_type->data.error_union.err_set_type;
15646 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
15647 ZigType *promise_type = get_promise_type(ira->codegen, return_type);
15648 ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
1564914919
15650 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(),
15651 async_return_type, nullptr, true, true, false);
15652 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
14920 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry);
14921 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
14922 frame_type, nullptr, true, true, false);
14923 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
1565314924 return result_loc;
1565414925 }
15655
15656 return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
15657 casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc,
15658 async_return_type);
14926 result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
14927 if (type_is_invalid(result_loc->value.type))
14928 return ira->codegen->invalid_instruction;
14929 return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
14930 casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base;
1565914931}
15660
1566114932static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
1566214933 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
1566314934{
......@@ -16004,20 +15275,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1600415275 }
1600515276 return ira->codegen->invalid_instruction;
1600615277 }
16007 if (fn_type_id->cc == CallingConventionAsync && !call_instruction->is_async) {
16008 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("must use async keyword to call async function"));
16009 if (fn_proto_node) {
16010 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
16011 }
16012 return ira->codegen->invalid_instruction;
16013 }
16014 if (fn_type_id->cc != CallingConventionAsync && call_instruction->is_async) {
16015 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("cannot use async keyword to call non-async function"));
16016 if (fn_proto_node) {
16017 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
16018 }
16019 return ira->codegen->invalid_instruction;
16020 }
1602115278
1602215279
1602315280 if (fn_type_id->is_var_args) {
......@@ -16354,33 +15611,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1635415611 break;
1635515612 }
1635615613 }
16357 IrInstruction *async_allocator_inst = nullptr;
16358 if (call_instruction->is_async) {
16359 AstNode *async_allocator_type_node = fn_proto_node->data.fn_proto.async_allocator_type;
16360 if (async_allocator_type_node != nullptr) {
16361 ZigType *async_allocator_type = ir_analyze_type_expr(ira, impl_fn->child_scope, async_allocator_type_node);
16362 if (type_is_invalid(async_allocator_type))
16363 return ira->codegen->invalid_instruction;
16364 inst_fn_type_id.async_allocator_type = async_allocator_type;
16365 }
16366 IrInstruction *uncasted_async_allocator_inst;
16367 if (call_instruction->async_allocator == nullptr) {
16368 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
16369 ImplicitAllocatorIdLocalVar);
16370 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16371 return ira->codegen->invalid_instruction;
16372 } else {
16373 uncasted_async_allocator_inst = call_instruction->async_allocator->child;
16374 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16375 return ira->codegen->invalid_instruction;
16376 }
16377 if (inst_fn_type_id.async_allocator_type == nullptr) {
16378 inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
16379 }
16380 async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
16381 if (type_is_invalid(async_allocator_inst->value.type))
16382 return ira->codegen->invalid_instruction;
16383 }
1638415614
1638515615 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
1638615616 if (existing_entry) {
......@@ -16423,17 +15653,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1642315653 size_t impl_param_count = impl_fn_type_id->param_count;
1642415654 if (call_instruction->is_async) {
1642515655 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
16426 fn_ref, casted_args, impl_param_count, async_allocator_inst);
15656 nullptr, casted_args, impl_param_count, casted_new_stack);
1642715657 return ir_finish_anal(ira, result);
1642815658 }
1642915659
16430 assert(async_allocator_inst == nullptr);
16431 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
15660 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15661 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15662 parent_fn_entry->inferred_async_fn = impl_fn;
15663 }
15664
15665 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
1643215666 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
16433 call_instruction->is_async, nullptr, casted_new_stack, result_loc,
15667 false, casted_new_stack, result_loc,
1643415668 impl_fn_type_id->return_type);
1643515669
16436 return ir_finish_anal(ira, new_call_instruction);
15670 parent_fn_entry->call_list.append(new_call_instruction);
15671
15672 return ir_finish_anal(ira, &new_call_instruction->base);
1643715673 }
1643815674
1643915675 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
......@@ -16475,20 +15711,56 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1647515711 IrInstruction *old_arg = call_instruction->args[call_i]->child;
1647615712 if (type_is_invalid(old_arg->value.type))
1647715713 return ira->codegen->invalid_instruction;
16478 IrInstruction *casted_arg;
16479 if (next_arg_index < src_param_count) {
16480 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
16481 if (type_is_invalid(param_type))
16482 return ira->codegen->invalid_instruction;
16483 casted_arg = ir_implicit_cast(ira, old_arg, param_type);
16484 if (type_is_invalid(casted_arg->value.type))
16485 return ira->codegen->invalid_instruction;
15714
15715 if (old_arg->value.type->id == ZigTypeIdArgTuple) {
15716 for (size_t arg_tuple_i = old_arg->value.data.x_arg_tuple.start_index;
15717 arg_tuple_i < old_arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
15718 {
15719 ZigVar *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
15720 if (arg_var == nullptr) {
15721 ir_add_error(ira, old_arg,
15722 buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
15723 return ira->codegen->invalid_instruction;
15724 }
15725 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, old_arg, arg_var);
15726 if (type_is_invalid(arg_var_ptr_inst->value.type))
15727 return ira->codegen->invalid_instruction;
15728
15729 IrInstruction *arg_tuple_arg = ir_get_deref(ira, old_arg, arg_var_ptr_inst, nullptr);
15730 if (type_is_invalid(arg_tuple_arg->value.type))
15731 return ira->codegen->invalid_instruction;
15732
15733 IrInstruction *casted_arg;
15734 if (next_arg_index < src_param_count) {
15735 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
15736 if (type_is_invalid(param_type))
15737 return ira->codegen->invalid_instruction;
15738 casted_arg = ir_implicit_cast(ira, arg_tuple_arg, param_type);
15739 if (type_is_invalid(casted_arg->value.type))
15740 return ira->codegen->invalid_instruction;
15741 } else {
15742 casted_arg = arg_tuple_arg;
15743 }
15744
15745 casted_args[next_arg_index] = casted_arg;
15746 next_arg_index += 1;
15747 }
1648615748 } else {
16487 casted_arg = old_arg;
16488 }
15749 IrInstruction *casted_arg;
15750 if (next_arg_index < src_param_count) {
15751 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
15752 if (type_is_invalid(param_type))
15753 return ira->codegen->invalid_instruction;
15754 casted_arg = ir_implicit_cast(ira, old_arg, param_type);
15755 if (type_is_invalid(casted_arg->value.type))
15756 return ira->codegen->invalid_instruction;
15757 } else {
15758 casted_arg = old_arg;
15759 }
1648915760
16490 casted_args[next_arg_index] = casted_arg;
16491 next_arg_index += 1;
15761 casted_args[next_arg_index] = casted_arg;
15762 next_arg_index += 1;
15763 }
1649215764 }
1649315765
1649415766 assert(next_arg_index == call_param_count);
......@@ -16497,32 +15769,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1649715769 if (type_is_invalid(return_type))
1649815770 return ira->codegen->invalid_instruction;
1649915771
16500 if (call_instruction->is_async) {
16501 IrInstruction *uncasted_async_allocator_inst;
16502 if (call_instruction->async_allocator == nullptr) {
16503 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
16504 ImplicitAllocatorIdLocalVar);
16505 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16506 return ira->codegen->invalid_instruction;
16507 } else {
16508 uncasted_async_allocator_inst = call_instruction->async_allocator->child;
16509 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16510 return ira->codegen->invalid_instruction;
16511
16512 }
16513 IrInstruction *async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, fn_type_id->async_allocator_type);
16514 if (type_is_invalid(async_allocator_inst->value.type))
16515 return ira->codegen->invalid_instruction;
15772 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
15773 ir_add_error(ira, &call_instruction->base,
15774 buf_sprintf("no-inline call of inline function"));
15775 return ira->codegen->invalid_instruction;
15776 }
1651615777
15778 if (call_instruction->is_async) {
1651715779 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
16518 casted_args, call_param_count, async_allocator_inst);
15780 casted_args, call_param_count, casted_new_stack);
1651915781 return ir_finish_anal(ira, result);
1652015782 }
1652115783
16522 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
16523 ir_add_error(ira, &call_instruction->base,
16524 buf_sprintf("no-inline call of inline function"));
16525 return ira->codegen->invalid_instruction;
15784 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15785 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15786 parent_fn_entry->inferred_async_fn = fn_entry;
1652615787 }
1652715788
1652815789 IrInstruction *result_loc;
......@@ -16536,10 +15797,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1653615797 result_loc = nullptr;
1653715798 }
1653815799
16539 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
16540 call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack,
15800 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
15801 call_param_count, casted_args, fn_inline, false, casted_new_stack,
1654115802 result_loc, return_type);
16542 return ir_finish_anal(ira, new_call_instruction);
15803 parent_fn_entry->call_list.append(new_call_instruction);
15804 return ir_finish_anal(ira, &new_call_instruction->base);
1654315805}
1654415806
1654515807static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {
......@@ -16684,7 +15946,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
1668415946 zig_unreachable();
1668515947}
1668615948
16687static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
15949static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
1668815950 Error err;
1668915951 IrInstruction *value = un_op_instruction->value->child;
1669015952 ZigType *type_entry = ir_resolve_type(ira, value);
......@@ -16718,8 +15980,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
1671815980 case ZigTypeIdFn:
1671915981 case ZigTypeIdBoundFn:
1672015982 case ZigTypeIdArgTuple:
16721 case ZigTypeIdPromise:
15983 case ZigTypeIdFnFrame:
15984 case ZigTypeIdAnyFrame:
1672215985 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));
15986
1672315987 case ZigTypeIdUnreachable:
1672415988 case ZigTypeIdOpaque:
1672515989 ir_add_error_node(ira, un_op_instruction->base.source_node,
......@@ -16883,7 +16147,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
1688316147 return result;
1688416148 }
1688516149 case IrUnOpOptional:
16886 return ir_analyze_maybe(ira, instruction);
16150 return ir_analyze_optional_type(ira, instruction);
1688716151 }
1688816152 zig_unreachable();
1688916153}
......@@ -18443,6 +17707,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
1844317707 return ir_const_void(ira, &instruction->base);
1844417708}
1844517709
17710static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira,
17711 IrInstructionAnyFrameType *instruction)
17712{
17713 ZigType *payload_type = nullptr;
17714 if (instruction->payload_type != nullptr) {
17715 payload_type = ir_resolve_type(ira, instruction->payload_type->child);
17716 if (type_is_invalid(payload_type))
17717 return ira->codegen->invalid_instruction;
17718 }
17719
17720 ZigType *any_frame_type = get_any_frame_type(ira->codegen, payload_type);
17721 return ir_const_type(ira, &instruction->base, any_frame_type);
17722}
17723
1844617724static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1844717725 IrInstructionSliceType *slice_type_instruction)
1844817726{
......@@ -18490,8 +17768,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1849017768 case ZigTypeIdUnion:
1849117769 case ZigTypeIdFn:
1849217770 case ZigTypeIdBoundFn:
18493 case ZigTypeIdPromise:
1849417771 case ZigTypeIdVector:
17772 case ZigTypeIdFnFrame:
17773 case ZigTypeIdAnyFrame:
1849517774 {
1849617775 ResolveStatus needed_status = (align_bytes == 0) ?
1849717776 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
......@@ -18605,8 +17884,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
1860517884 case ZigTypeIdUnion:
1860617885 case ZigTypeIdFn:
1860717886 case ZigTypeIdBoundFn:
18608 case ZigTypeIdPromise:
1860917887 case ZigTypeIdVector:
17888 case ZigTypeIdFnFrame:
17889 case ZigTypeIdAnyFrame:
1861017890 {
1861117891 if ((err = ensure_complete_type(ira->codegen, child_type)))
1861217892 return ira->codegen->invalid_instruction;
......@@ -18617,22 +17897,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
1861717897 zig_unreachable();
1861817898}
1861917899
18620static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) {
18621 ZigType *promise_type;
18622
18623 if (instruction->payload_type == nullptr) {
18624 promise_type = ira->codegen->builtin_types.entry_promise;
18625 } else {
18626 ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child);
18627 if (type_is_invalid(payload_type))
18628 return ira->codegen->invalid_instruction;
18629
18630 promise_type = get_promise_type(ira->codegen, payload_type);
18631 }
18632
18633 return ir_const_type(ira, &instruction->base, promise_type);
18634}
18635
1863617900static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
1863717901 IrInstructionSizeOf *size_of_instruction)
1863817902{
......@@ -18672,8 +17936,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
1867217936 case ZigTypeIdEnum:
1867317937 case ZigTypeIdUnion:
1867417938 case ZigTypeIdFn:
18675 case ZigTypeIdPromise:
1867617939 case ZigTypeIdVector:
17940 case ZigTypeIdFnFrame:
17941 case ZigTypeIdAnyFrame:
1867717942 {
1867817943 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
1867917944 return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);
......@@ -19159,7 +18424,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1915918424 case ZigTypeIdComptimeInt:
1916018425 case ZigTypeIdEnumLiteral:
1916118426 case ZigTypeIdPointer:
19162 case ZigTypeIdPromise:
1916318427 case ZigTypeIdFn:
1916418428 case ZigTypeIdErrorSet: {
1916518429 if (pointee_val) {
......@@ -19238,6 +18502,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1923818502 case ZigTypeIdArgTuple:
1923918503 case ZigTypeIdOpaque:
1924018504 case ZigTypeIdVector:
18505 case ZigTypeIdFnFrame:
18506 case ZigTypeIdAnyFrame:
1924118507 ir_add_error(ira, &switch_target_instruction->base,
1924218508 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
1924318509 return ira->codegen->invalid_instruction;
......@@ -20672,32 +19938,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2067219938
2067319939 break;
2067419940 }
20675 case ZigTypeIdPromise:
20676 {
20677 result = create_const_vals(1);
20678 result->special = ConstValSpecialStatic;
20679 result->type = ir_type_info_get_type(ira, "Promise", nullptr);
20680
20681 ConstExprValue *fields = create_const_vals(1);
20682 result->data.x_struct.fields = fields;
20683
20684 // child: ?type
20685 ensure_field_index(result->type, "child", 0);
20686 fields[0].special = ConstValSpecialStatic;
20687 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
19941 case ZigTypeIdAnyFrame: {
19942 result = create_const_vals(1);
19943 result->special = ConstValSpecialStatic;
19944 result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr);
2068819945
20689 if (type_entry->data.promise.result_type == nullptr)
20690 fields[0].data.x_optional = nullptr;
20691 else {
20692 ConstExprValue *child_type = create_const_vals(1);
20693 child_type->special = ConstValSpecialStatic;
20694 child_type->type = ira->codegen->builtin_types.entry_type;
20695 child_type->data.x_type = type_entry->data.promise.result_type;
20696 fields[0].data.x_optional = child_type;
20697 }
19946 ConstExprValue *fields = create_const_vals(1);
19947 result->data.x_struct.fields = fields;
2069819948
20699 break;
20700 }
19949 // child: ?type
19950 ensure_field_index(result->type, "child", 0);
19951 fields[0].special = ConstValSpecialStatic;
19952 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
19953 fields[0].data.x_optional = (type_entry->data.any_frame.result_type == nullptr) ? nullptr :
19954 create_const_type(ira->codegen, type_entry->data.any_frame.result_type);
19955 break;
19956 }
2070119957 case ZigTypeIdEnum:
2070219958 {
2070319959 result = create_const_vals(1);
......@@ -21007,7 +20263,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2100720263 result->special = ConstValSpecialStatic;
2100820264 result->type = ir_type_info_get_type(ira, "Fn", nullptr);
2100920265
21010 ConstExprValue *fields = create_const_vals(6);
20266 ConstExprValue *fields = create_const_vals(5);
2101120267 result->data.x_struct.fields = fields;
2101220268
2101320269 // calling_convention: TypeInfo.CallingConvention
......@@ -21038,20 +20294,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2103820294 return_type->special = ConstValSpecialStatic;
2103920295 return_type->type = ira->codegen->builtin_types.entry_type;
2104020296 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
21041 fields[3].data.x_optional = return_type;
21042 }
21043 // async_allocator_type: type
21044 ensure_field_index(result->type, "async_allocator_type", 4);
21045 fields[4].special = ConstValSpecialStatic;
21046 fields[4].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
21047 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
21048 fields[4].data.x_optional = nullptr;
21049 else {
21050 ConstExprValue *async_alloc_type = create_const_vals(1);
21051 async_alloc_type->special = ConstValSpecialStatic;
21052 async_alloc_type->type = ira->codegen->builtin_types.entry_type;
21053 async_alloc_type->data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
21054 fields[4].data.x_optional = async_alloc_type;
20297 fields[3].data.x_optional = return_type;
2105520298 }
2105620299 // args: []TypeInfo.FnArg
2105720300 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);
......@@ -21067,10 +20310,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2106720310 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
2106820311 fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
2106920312
21070 init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
20313 init_const_slice(ira->codegen, &fields[4], fn_arg_array, 0, fn_arg_count, false);
2107120314
21072 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
21073 {
20315 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
2107420316 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
2107520317 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index];
2107620318
......@@ -21117,6 +20359,8 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2111720359
2111820360 break;
2111920361 }
20362 case ZigTypeIdFnFrame:
20363 zig_panic("TODO @typeInfo for async function frames");
2112020364 }
2112120365
2112220366 assert(result != nullptr);
......@@ -22830,11 +22074,45 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns
2283022074 return result;
2283122075}
2283222076
22833static IrInstruction *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructionHandle *instruction) {
22077static IrInstruction *ir_analyze_instruction_frame_handle(IrAnalyze *ira, IrInstructionFrameHandle *instruction) {
22078 ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
22079 ir_assert(fn != nullptr, &instruction->base);
22080
22081 if (fn->inferred_async_node == nullptr) {
22082 fn->inferred_async_node = instruction->base.source_node;
22083 }
22084
22085 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn);
22086 ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false);
22087
2283422088 IrInstruction *result = ir_build_handle(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
22835 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
22836 assert(fn_entry != nullptr);
22837 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
22089 result->value.type = ptr_frame_type;
22090 return result;
22091}
22092
22093static IrInstruction *ir_analyze_instruction_frame_type(IrAnalyze *ira, IrInstructionFrameType *instruction) {
22094 ZigFn *fn = ir_resolve_fn(ira, instruction->fn->child);
22095 if (fn == nullptr)
22096 return ira->codegen->invalid_instruction;
22097
22098 ZigType *ty = get_fn_frame_type(ira->codegen, fn);
22099 return ir_const_type(ira, &instruction->base, ty);
22100}
22101
22102static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstructionFrameSizeSrc *instruction) {
22103 IrInstruction *fn = instruction->fn->child;
22104 if (type_is_invalid(fn->value.type))
22105 return ira->codegen->invalid_instruction;
22106
22107 if (fn->value.type->id != ZigTypeIdFn) {
22108 ir_add_error(ira, fn,
22109 buf_sprintf("expected function, found '%s'", buf_ptr(&fn->value.type->name)));
22110 return ira->codegen->invalid_instruction;
22111 }
22112
22113 IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope,
22114 instruction->base.source_node, fn);
22115 result->value.type = ira->codegen->builtin_types.entry_usize;
2283822116 return result;
2283922117}
2284022118
......@@ -22869,7 +22147,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2286922147 case ZigTypeIdInt:
2287022148 case ZigTypeIdFloat:
2287122149 case ZigTypeIdPointer:
22872 case ZigTypeIdPromise:
2287322150 case ZigTypeIdArray:
2287422151 case ZigTypeIdStruct:
2287522152 case ZigTypeIdOptional:
......@@ -22879,6 +22156,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2287922156 case ZigTypeIdUnion:
2288022157 case ZigTypeIdFn:
2288122158 case ZigTypeIdVector:
22159 case ZigTypeIdFnFrame:
22160 case ZigTypeIdAnyFrame:
2288222161 {
2288322162 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
2288422163 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
......@@ -22993,19 +22272,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
2299322272 return result;
2299422273}
2299522274
22996static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstructionResultPtr *instruction) {
22997 IrInstruction *result = instruction->result->child;
22998 if (type_is_invalid(result->value.type))
22999 return result;
23000
23001 if (instruction->result_loc->written && instruction->result_loc->resolved_loc != nullptr &&
23002 !instr_is_comptime(result))
23003 {
23004 return instruction->result_loc->resolved_loc;
23005 }
23006 return ir_get_ref(ira, &instruction->base, result, true, false);
23007}
23008
2300922275static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,
2301022276 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {
2301122277 if (float_type->id == ZigTypeIdComptimeFloat) {
......@@ -23130,11 +22396,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
2313022396 if (type_is_invalid(base_ptr->value.type))
2313122397 return ira->codegen->invalid_instruction;
2313222398
23133 IrInstruction *value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr);
22399 IrInstruction *value;
22400 if (instruction->base_ptr_is_payload) {
22401 value = base_ptr;
22402 } else {
22403 value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr);
22404 }
22405
2313422406 ZigType *type_entry = value->value.type;
2313522407 if (type_is_invalid(type_entry))
2313622408 return ira->codegen->invalid_instruction;
23137
2313822409 if (type_entry->id == ZigTypeIdErrorUnion) {
2313922410 if (instr_is_comptime(value)) {
2314022411 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
......@@ -23428,18 +22699,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
2342822699 return ira->codegen->invalid_instruction;
2342922700 }
2343022701
23431 if (fn_type_id.cc == CallingConventionAsync) {
23432 if (instruction->async_allocator_type_value == nullptr) {
23433 ir_add_error(ira, &instruction->base,
23434 buf_sprintf("async fn proto missing allocator type"));
23435 return ira->codegen->invalid_instruction;
23436 }
23437 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child;
23438 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
23439 if (type_is_invalid(fn_type_id.async_allocator_type))
23440 return ira->codegen->invalid_instruction;
23441 }
23442
2344322702 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
2344422703}
2344522704
......@@ -23678,7 +22937,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
2367822937 if (type_is_invalid(statement_type))
2367922938 return ira->codegen->invalid_instruction;
2368022939
23681 if (statement_type->id != ZigTypeIdVoid) {
22940 if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) {
2368222941 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
2368322942 }
2368422943
......@@ -23933,7 +23192,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2393323192 case ZigTypeIdEnumLiteral:
2393423193 case ZigTypeIdUndefined:
2393523194 case ZigTypeIdNull:
23936 case ZigTypeIdPromise:
2393723195 case ZigTypeIdErrorUnion:
2393823196 case ZigTypeIdErrorSet:
2393923197 zig_unreachable();
......@@ -24043,6 +23301,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2404323301 zig_panic("TODO buf_write_value_bytes fn type");
2404423302 case ZigTypeIdUnion:
2404523303 zig_panic("TODO buf_write_value_bytes union type");
23304 case ZigTypeIdFnFrame:
23305 zig_panic("TODO buf_write_value_bytes async fn frame type");
23306 case ZigTypeIdAnyFrame:
23307 zig_panic("TODO buf_write_value_bytes anyframe type");
2404623308 }
2404723309 zig_unreachable();
2404823310}
......@@ -24087,7 +23349,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
2408723349 case ZigTypeIdEnumLiteral:
2408823350 case ZigTypeIdUndefined:
2408923351 case ZigTypeIdNull:
24090 case ZigTypeIdPromise:
2409123352 zig_unreachable();
2409223353 case ZigTypeIdVoid:
2409323354 return ErrorNone;
......@@ -24223,6 +23484,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
2422323484 zig_panic("TODO buf_read_value_bytes fn type");
2422423485 case ZigTypeIdUnion:
2422523486 zig_panic("TODO buf_read_value_bytes union type");
23487 case ZigTypeIdFnFrame:
23488 zig_panic("TODO buf_read_value_bytes async fn frame type");
23489 case ZigTypeIdAnyFrame:
23490 zig_panic("TODO buf_read_value_bytes anyframe type");
2422623491 }
2422723492 zig_unreachable();
2422823493}
......@@ -24573,184 +23838,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2457323838 }
2457423839}
2457523840
24576static IrInstruction *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
24577 IrInstruction *target_inst = instruction->target->child;
24578 if (type_is_invalid(target_inst->value.type))
24579 return ira->codegen->invalid_instruction;
24580 IrInstruction *casted_target = ir_implicit_cast(ira, target_inst, ira->codegen->builtin_types.entry_promise);
24581 if (type_is_invalid(casted_target->value.type))
24582 return ira->codegen->invalid_instruction;
24583
24584 IrInstruction *result = ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_target);
24585 result->value.type = ira->codegen->builtin_types.entry_void;
24586 result->value.special = ConstValSpecialStatic;
24587 return result;
24588}
24589
24590static IrInstruction *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) {
24591 IrInstruction *promise_ptr = instruction->promise_ptr->child;
24592 if (type_is_invalid(promise_ptr->value.type))
24593 return ira->codegen->invalid_instruction;
24594
24595 IrInstruction *result = ir_build_coro_id(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24596 promise_ptr);
24597 result->value.type = ira->codegen->builtin_types.entry_usize;
24598 return result;
24599}
24600
24601static IrInstruction *ir_analyze_instruction_coro_alloc(IrAnalyze *ira, IrInstructionCoroAlloc *instruction) {
24602 IrInstruction *coro_id = instruction->coro_id->child;
24603 if (type_is_invalid(coro_id->value.type))
24604 return ira->codegen->invalid_instruction;
24605
24606 IrInstruction *result = ir_build_coro_alloc(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24607 coro_id);
24608 result->value.type = ira->codegen->builtin_types.entry_bool;
24609 return result;
24610}
24611
24612static IrInstruction *ir_analyze_instruction_coro_size(IrAnalyze *ira, IrInstructionCoroSize *instruction) {
24613 IrInstruction *result = ir_build_coro_size(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
24614 result->value.type = ira->codegen->builtin_types.entry_usize;
24615 return result;
24616}
24617
24618static IrInstruction *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstructionCoroBegin *instruction) {
24619 IrInstruction *coro_id = instruction->coro_id->child;
24620 if (type_is_invalid(coro_id->value.type))
24621 return ira->codegen->invalid_instruction;
24622
24623 IrInstruction *coro_mem_ptr = instruction->coro_mem_ptr->child;
24624 if (type_is_invalid(coro_mem_ptr->value.type))
24625 return ira->codegen->invalid_instruction;
24626
24627 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24628 ir_assert(fn_entry != nullptr, &instruction->base);
24629 IrInstruction *result = ir_build_coro_begin(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24630 coro_id, coro_mem_ptr);
24631 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
24632 return result;
24633}
24634
24635static IrInstruction *ir_analyze_instruction_get_implicit_allocator(IrAnalyze *ira, IrInstructionGetImplicitAllocator *instruction) {
24636 return ir_get_implicit_allocator(ira, &instruction->base, instruction->id);
24637}
24638
24639static IrInstruction *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, IrInstructionCoroAllocFail *instruction) {
24640 IrInstruction *err_val = instruction->err_val->child;
24641 if (type_is_invalid(err_val->value.type))
24642 return ir_unreach_error(ira);
24643
24644 IrInstruction *result = ir_build_coro_alloc_fail(&ira->new_irb, instruction->base.scope, instruction->base.source_node, err_val);
24645 result->value.type = ira->codegen->builtin_types.entry_unreachable;
24646 return ir_finish_anal(ira, result);
24647}
24648
24649static IrInstruction *ir_analyze_instruction_coro_suspend(IrAnalyze *ira, IrInstructionCoroSuspend *instruction) {
24650 IrInstruction *save_point = nullptr;
24651 if (instruction->save_point != nullptr) {
24652 save_point = instruction->save_point->child;
24653 if (type_is_invalid(save_point->value.type))
24654 return ira->codegen->invalid_instruction;
24655 }
24656
24657 IrInstruction *is_final = instruction->is_final->child;
24658 if (type_is_invalid(is_final->value.type))
24659 return ira->codegen->invalid_instruction;
24660
24661 IrInstruction *result = ir_build_coro_suspend(&ira->new_irb, instruction->base.scope,
24662 instruction->base.source_node, save_point, is_final);
24663 result->value.type = ira->codegen->builtin_types.entry_u8;
24664 return result;
24665}
24666
24667static IrInstruction *ir_analyze_instruction_coro_end(IrAnalyze *ira, IrInstructionCoroEnd *instruction) {
24668 IrInstruction *result = ir_build_coro_end(&ira->new_irb, instruction->base.scope,
24669 instruction->base.source_node);
24670 result->value.type = ira->codegen->builtin_types.entry_void;
24671 return result;
24672}
24673
24674static IrInstruction *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstructionCoroFree *instruction) {
24675 IrInstruction *coro_id = instruction->coro_id->child;
24676 if (type_is_invalid(coro_id->value.type))
24677 return ira->codegen->invalid_instruction;
24678
24679 IrInstruction *coro_handle = instruction->coro_handle->child;
24680 if (type_is_invalid(coro_handle->value.type))
24681 return ira->codegen->invalid_instruction;
24682
24683 IrInstruction *result = ir_build_coro_free(&ira->new_irb, instruction->base.scope,
24684 instruction->base.source_node, coro_id, coro_handle);
24685 ZigType *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
24686 result->value.type = get_optional_type(ira->codegen, ptr_type);
24687 return result;
24688}
24689
24690static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {
24691 IrInstruction *awaiter_handle = instruction->awaiter_handle->child;
24692 if (type_is_invalid(awaiter_handle->value.type))
24693 return ira->codegen->invalid_instruction;
24694
24695 IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise);
24696 if (type_is_invalid(casted_target->value.type))
24697 return ira->codegen->invalid_instruction;
24698
24699 IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope,
24700 instruction->base.source_node, casted_target);
24701 result->value.type = ira->codegen->builtin_types.entry_void;
24702 return result;
24703}
24704
24705static IrInstruction *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstructionCoroSave *instruction) {
24706 IrInstruction *coro_handle = instruction->coro_handle->child;
24707 if (type_is_invalid(coro_handle->value.type))
24708 return ira->codegen->invalid_instruction;
24709
24710 IrInstruction *result = ir_build_coro_save(&ira->new_irb, instruction->base.scope,
24711 instruction->base.source_node, coro_handle);
24712 result->value.type = ira->codegen->builtin_types.entry_usize;
24713 return result;
24714}
24715
24716static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInstructionCoroPromise *instruction) {
24717 IrInstruction *coro_handle = instruction->coro_handle->child;
24718 if (type_is_invalid(coro_handle->value.type))
24719 return ira->codegen->invalid_instruction;
24720
24721 if (coro_handle->value.type->id != ZigTypeIdPromise ||
24722 coro_handle->value.type->data.promise.result_type == nullptr)
24723 {
24724 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
24725 buf_ptr(&coro_handle->value.type->name)));
24726 return ira->codegen->invalid_instruction;
24727 }
24728
24729 ZigType *coro_frame_type = get_promise_frame_type(ira->codegen,
24730 coro_handle->value.type->data.promise.result_type);
24731
24732 IrInstruction *result = ir_build_coro_promise(&ira->new_irb, instruction->base.scope,
24733 instruction->base.source_node, coro_handle);
24734 result->value.type = get_pointer_to_type(ira->codegen, coro_frame_type, false);
24735 return result;
24736}
24737
24738static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {
24739 IrInstruction *realloc_fn = instruction->realloc_fn->child;
24740 if (type_is_invalid(realloc_fn->value.type))
24741 return ira->codegen->invalid_instruction;
24742
24743 IrInstruction *coro_size = instruction->coro_size->child;
24744 if (type_is_invalid(coro_size->value.type))
24745 return ira->codegen->invalid_instruction;
24746
24747 IrInstruction *result = ir_build_coro_alloc_helper(&ira->new_irb, instruction->base.scope,
24748 instruction->base.source_node, realloc_fn, coro_size);
24749 ZigType *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
24750 result->value.type = get_optional_type(ira->codegen, u8_ptr_type);
24751 return result;
24752}
24753
2475423841static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
2475523842 ZigType *operand_type = ir_resolve_type(ira, op);
2475623843 if (type_is_invalid(operand_type))
......@@ -24882,65 +23969,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
2488223969 return result;
2488323970}
2488423971
24885static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
24886 ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child);
24887 if (type_is_invalid(promise_type))
24888 return ira->codegen->invalid_instruction;
24889
24890 if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) {
24891 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
24892 buf_ptr(&promise_type->name)));
24893 return ira->codegen->invalid_instruction;
24894 }
24895
24896 return ir_const_type(ira, &instruction->base, promise_type->data.promise.result_type);
24897}
24898
24899static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) {
24900 ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child);
24901 if (type_is_invalid(promise_result_type))
24902 return ira->codegen->invalid_instruction;
24903
24904 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24905 ir_assert(fn_entry != nullptr, &instruction->base);
24906
24907 if (type_can_fail(promise_result_type)) {
24908 fn_entry->calls_or_awaits_errorable_fn = true;
24909 }
24910
24911 return ir_const_void(ira, &instruction->base);
24912}
24913
24914static IrInstruction *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
24915 IrInstructionMergeErrRetTraces *instruction)
24916{
24917 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->child;
24918 if (type_is_invalid(coro_promise_ptr->value.type))
24919 return ira->codegen->invalid_instruction;
24920
24921 ir_assert(coro_promise_ptr->value.type->id == ZigTypeIdPointer, &instruction->base);
24922 ZigType *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
24923 ir_assert(promise_frame_type->id == ZigTypeIdStruct, &instruction->base);
24924 ZigType *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
24925
24926 if (!type_can_fail(promise_result_type)) {
24927 return ir_const_void(ira, &instruction->base);
24928 }
24929
24930 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->child;
24931 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
24932 return ira->codegen->invalid_instruction;
24933
24934 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->child;
24935 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
24936 return ira->codegen->invalid_instruction;
24937
24938 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
24939 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
24940 result->value.type = ira->codegen->builtin_types.entry_void;
24941 return result;
24942}
24943
2494423972static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
2494523973 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
2494623974 instruction->base.source_node);
......@@ -24948,17 +23976,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I
2494823976 return result;
2494923977}
2495023978
24951static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
24952 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->child;
24953 if (type_is_invalid(err_ret_trace_ptr->value.type))
24954 return ira->codegen->invalid_instruction;
24955
24956 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
24957 instruction->base.source_node, err_ret_trace_ptr);
24958 result->value.type = ira->codegen->builtin_types.entry_void;
24959 return result;
24960}
24961
2496223979static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
2496323980 ConstExprValue *op, ConstExprValue *out_val) {
2496423981 assert(ira && source_instr && float_type && out_val && op);
......@@ -25485,6 +24502,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i
2548524502 union_type, field_name, field_result_loc, result_loc);
2548624503}
2548724504
24505static IrInstruction *ir_analyze_instruction_suspend_begin(IrAnalyze *ira, IrInstructionSuspendBegin *instruction) {
24506 IrInstructionSuspendBegin *result = ir_build_suspend_begin(&ira->new_irb, instruction->base.scope,
24507 instruction->base.source_node);
24508 return &result->base;
24509}
24510
24511static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,
24512 IrInstructionSuspendFinish *instruction)
24513{
24514 IrInstruction *begin_base = instruction->begin->base.child;
24515 if (type_is_invalid(begin_base->value.type))
24516 return ira->codegen->invalid_instruction;
24517 ir_assert(begin_base->id == IrInstructionIdSuspendBegin, &instruction->base);
24518 IrInstructionSuspendBegin *begin = reinterpret_cast<IrInstructionSuspendBegin *>(begin_base);
24519
24520 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24521 ir_assert(fn_entry != nullptr, &instruction->base);
24522
24523 if (fn_entry->inferred_async_node == nullptr) {
24524 fn_entry->inferred_async_node = instruction->base.source_node;
24525 }
24526
24527 return ir_build_suspend_finish(&ira->new_irb, instruction->base.scope, instruction->base.source_node, begin);
24528}
24529
24530static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,
24531 IrInstruction *frame_ptr)
24532{
24533 if (type_is_invalid(frame_ptr->value.type))
24534 return ira->codegen->invalid_instruction;
24535
24536 ZigType *result_type;
24537 IrInstruction *frame;
24538 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24539 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24540 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24541 {
24542 result_type = frame_ptr->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;
24543 frame = frame_ptr;
24544 } else {
24545 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);
24546 if (frame->value.type->id == ZigTypeIdPointer &&
24547 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&
24548 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24549 {
24550 result_type = frame->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;
24551 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||
24552 frame->value.type->data.any_frame.result_type == nullptr)
24553 {
24554 ir_add_error(ira, source_instr,
24555 buf_sprintf("expected anyframe->T, found '%s'", buf_ptr(&frame->value.type->name)));
24556 return ira->codegen->invalid_instruction;
24557 } else {
24558 result_type = frame->value.type->data.any_frame.result_type;
24559 }
24560 }
24561
24562 ZigType *any_frame_type = get_any_frame_type(ira->codegen, result_type);
24563 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24564 if (type_is_invalid(casted_frame->value.type))
24565 return ira->codegen->invalid_instruction;
24566
24567 return casted_frame;
24568}
24569
24570static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {
24571 IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child);
24572 if (type_is_invalid(frame->value.type))
24573 return ira->codegen->invalid_instruction;
24574
24575 ZigType *result_type = frame->value.type->data.any_frame.result_type;
24576
24577 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24578 ir_assert(fn_entry != nullptr, &instruction->base);
24579
24580 if (fn_entry->inferred_async_node == nullptr) {
24581 fn_entry->inferred_async_node = instruction->base.source_node;
24582 }
24583
24584 if (type_can_fail(result_type)) {
24585 fn_entry->calls_or_awaits_errorable_fn = true;
24586 }
24587
24588 IrInstruction *result_loc;
24589 if (type_has_bits(result_type)) {
24590 result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
24591 result_type, nullptr, true, true, true);
24592 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
24593 return result_loc;
24594 } else {
24595 result_loc = nullptr;
24596 }
24597
24598 IrInstruction *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);
24599 return ir_finish_anal(ira, result);
24600}
24601
24602static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {
24603 IrInstruction *frame_ptr = instruction->frame->child;
24604 if (type_is_invalid(frame_ptr->value.type))
24605 return ira->codegen->invalid_instruction;
24606
24607 IrInstruction *frame;
24608 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24609 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24610 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24611 {
24612 frame = frame_ptr;
24613 } else {
24614 frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr);
24615 }
24616
24617 ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr);
24618 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24619 if (type_is_invalid(casted_frame->value.type))
24620 return ira->codegen->invalid_instruction;
24621
24622 return ir_build_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame);
24623}
24624
24625static IrInstruction *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstructionSpillBegin *instruction) {
24626 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope))
24627 return ir_const_void(ira, &instruction->base);
24628
24629 IrInstruction *operand = instruction->operand->child;
24630 if (type_is_invalid(operand->value.type))
24631 return ira->codegen->invalid_instruction;
24632
24633 if (!type_has_bits(operand->value.type))
24634 return ir_const_void(ira, &instruction->base);
24635
24636 ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base);
24637 ira->new_irb.exec->need_err_code_spill = true;
24638
24639 IrInstructionSpillBegin *result = ir_build_spill_begin(&ira->new_irb, instruction->base.scope,
24640 instruction->base.source_node, operand, instruction->spill_id);
24641 return &result->base;
24642}
24643
24644static IrInstruction *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstructionSpillEnd *instruction) {
24645 IrInstruction *operand = instruction->begin->operand->child;
24646 if (type_is_invalid(operand->value.type))
24647 return ira->codegen->invalid_instruction;
24648
24649 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope) || !type_has_bits(operand->value.type))
24650 return operand;
24651
24652 ir_assert(instruction->begin->base.child->id == IrInstructionIdSpillBegin, &instruction->base);
24653 IrInstructionSpillBegin *begin = reinterpret_cast<IrInstructionSpillBegin *>(instruction->begin->base.child);
24654
24655 IrInstruction *result = ir_build_spill_end(&ira->new_irb, instruction->base.scope,
24656 instruction->base.source_node, begin);
24657 result->value.type = operand->value.type;
24658 return result;
24659}
24660
2548824661static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
2548924662 switch (instruction->id) {
2549024663 case IrInstructionIdInvalid:
......@@ -25512,6 +24685,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2551224685 case IrInstructionIdSliceGen:
2551324686 case IrInstructionIdRefGen:
2551424687 case IrInstructionIdTestErrGen:
24688 case IrInstructionIdFrameSizeGen:
24689 case IrInstructionIdAwaitGen:
2551524690 zig_unreachable();
2551624691
2551724692 case IrInstructionIdReturn:
......@@ -25552,6 +24727,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2555224727 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);
2555324728 case IrInstructionIdSetFloatMode:
2555424729 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);
24730 case IrInstructionIdAnyFrameType:
24731 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
2555524732 case IrInstructionIdSliceType:
2555624733 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
2555724734 case IrInstructionIdGlobalAsm:
......@@ -25560,8 +24737,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2556024737 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
2556124738 case IrInstructionIdArrayType:
2556224739 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
25563 case IrInstructionIdPromiseType:
25564 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
2556524740 case IrInstructionIdSizeOf:
2556624741 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
2556724742 case IrInstructionIdTestNonNull:
......@@ -25660,8 +24835,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2566024835 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
2566124836 case IrInstructionIdFrameAddress:
2566224837 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
25663 case IrInstructionIdHandle:
25664 return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);
24838 case IrInstructionIdFrameHandle:
24839 return ir_analyze_instruction_frame_handle(ira, (IrInstructionFrameHandle *)instruction);
24840 case IrInstructionIdFrameType:
24841 return ir_analyze_instruction_frame_type(ira, (IrInstructionFrameType *)instruction);
24842 case IrInstructionIdFrameSizeSrc:
24843 return ir_analyze_instruction_frame_size(ira, (IrInstructionFrameSizeSrc *)instruction);
2566524844 case IrInstructionIdAlignOf:
2566624845 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
2566724846 case IrInstructionIdOverflowOp:
......@@ -25716,8 +24895,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2571624895 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);
2571724896 case IrInstructionIdResetResult:
2571824897 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);
25719 case IrInstructionIdResultPtr:
25720 return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction);
2572124898 case IrInstructionIdOpaqueType:
2572224899 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
2572324900 case IrInstructionIdSetAlignStack:
......@@ -25732,50 +24909,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2573224909 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
2573324910 case IrInstructionIdErrorUnion:
2573424911 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
25735 case IrInstructionIdCancel:
25736 return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction);
25737 case IrInstructionIdCoroId:
25738 return ir_analyze_instruction_coro_id(ira, (IrInstructionCoroId *)instruction);
25739 case IrInstructionIdCoroAlloc:
25740 return ir_analyze_instruction_coro_alloc(ira, (IrInstructionCoroAlloc *)instruction);
25741 case IrInstructionIdCoroSize:
25742 return ir_analyze_instruction_coro_size(ira, (IrInstructionCoroSize *)instruction);
25743 case IrInstructionIdCoroBegin:
25744 return ir_analyze_instruction_coro_begin(ira, (IrInstructionCoroBegin *)instruction);
25745 case IrInstructionIdGetImplicitAllocator:
25746 return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction);
25747 case IrInstructionIdCoroAllocFail:
25748 return ir_analyze_instruction_coro_alloc_fail(ira, (IrInstructionCoroAllocFail *)instruction);
25749 case IrInstructionIdCoroSuspend:
25750 return ir_analyze_instruction_coro_suspend(ira, (IrInstructionCoroSuspend *)instruction);
25751 case IrInstructionIdCoroEnd:
25752 return ir_analyze_instruction_coro_end(ira, (IrInstructionCoroEnd *)instruction);
25753 case IrInstructionIdCoroFree:
25754 return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction);
25755 case IrInstructionIdCoroResume:
25756 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
25757 case IrInstructionIdCoroSave:
25758 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
25759 case IrInstructionIdCoroPromise:
25760 return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction);
25761 case IrInstructionIdCoroAllocHelper:
25762 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
2576324912 case IrInstructionIdAtomicRmw:
2576424913 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
2576524914 case IrInstructionIdAtomicLoad:
2576624915 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);
25767 case IrInstructionIdPromiseResultType:
25768 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
25769 case IrInstructionIdAwaitBookkeeping:
25770 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
2577124916 case IrInstructionIdSaveErrRetAddr:
2577224917 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
2577324918 case IrInstructionIdAddImplicitReturnType:
2577424919 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
25775 case IrInstructionIdMergeErrRetTraces:
25776 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
25777 case IrInstructionIdMarkErrRetTracePtr:
25778 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
2577924920 case IrInstructionIdFloatOp:
2578024921 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
2578124922 case IrInstructionIdMulAdd:
......@@ -25802,6 +24943,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2580224943 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);
2580324944 case IrInstructionIdUnionInitNamedField:
2580424945 return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction);
24946 case IrInstructionIdSuspendBegin:
24947 return ir_analyze_instruction_suspend_begin(ira, (IrInstructionSuspendBegin *)instruction);
24948 case IrInstructionIdSuspendFinish:
24949 return ir_analyze_instruction_suspend_finish(ira, (IrInstructionSuspendFinish *)instruction);
24950 case IrInstructionIdResume:
24951 return ir_analyze_instruction_resume(ira, (IrInstructionResume *)instruction);
24952 case IrInstructionIdAwaitSrc:
24953 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
24954 case IrInstructionIdSpillBegin:
24955 return ir_analyze_instruction_spill_begin(ira, (IrInstructionSpillBegin *)instruction);
24956 case IrInstructionIdSpillEnd:
24957 return ir_analyze_instruction_spill_end(ira, (IrInstructionSpillEnd *)instruction);
2580524958 }
2580624959 zig_unreachable();
2580724960}
......@@ -25818,9 +24971,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
2581824971 old_exec->analysis = ira;
2581924972 ira->codegen = codegen;
2582024973
25821 ZigFn *fn_entry = exec_fn_entry(old_exec);
25822 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
25823 ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type;
24974 ira->explicit_return_type = expected_type;
2582424975 ira->explicit_return_type_source_node = expected_type_source_node;
2582524976
2582624977 ira->old_irb.codegen = codegen;
......@@ -25918,19 +25069,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2591825069 case IrInstructionIdPtrType:
2591925070 case IrInstructionIdSetAlignStack:
2592025071 case IrInstructionIdExport:
25921 case IrInstructionIdCancel:
25922 case IrInstructionIdCoroId:
25923 case IrInstructionIdCoroBegin:
25924 case IrInstructionIdCoroAllocFail:
25925 case IrInstructionIdCoroEnd:
25926 case IrInstructionIdCoroResume:
25927 case IrInstructionIdCoroSave:
25928 case IrInstructionIdCoroAllocHelper:
25929 case IrInstructionIdAwaitBookkeeping:
2593025072 case IrInstructionIdSaveErrRetAddr:
2593125073 case IrInstructionIdAddImplicitReturnType:
25932 case IrInstructionIdMergeErrRetTraces:
25933 case IrInstructionIdMarkErrRetTracePtr:
2593425074 case IrInstructionIdAtomicRmw:
2593525075 case IrInstructionIdCmpxchgGen:
2593625076 case IrInstructionIdCmpxchgSrc:
......@@ -25945,6 +25085,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2594525085 case IrInstructionIdOptionalWrap:
2594625086 case IrInstructionIdVectorToArray:
2594725087 case IrInstructionIdResetResult:
25088 case IrInstructionIdSuspendBegin:
25089 case IrInstructionIdSuspendFinish:
25090 case IrInstructionIdResume:
25091 case IrInstructionIdAwaitSrc:
25092 case IrInstructionIdAwaitGen:
25093 case IrInstructionIdSpillBegin:
2594825094 return true;
2594925095
2595025096 case IrInstructionIdPhi:
......@@ -25963,8 +25109,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2596325109 case IrInstructionIdTypeOf:
2596425110 case IrInstructionIdStructFieldPtr:
2596525111 case IrInstructionIdArrayType:
25966 case IrInstructionIdPromiseType:
2596725112 case IrInstructionIdSliceType:
25113 case IrInstructionIdAnyFrameType:
2596825114 case IrInstructionIdSizeOf:
2596925115 case IrInstructionIdTestNonNull:
2597025116 case IrInstructionIdOptionalUnwrapPtr:
......@@ -25990,7 +25136,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2599025136 case IrInstructionIdAlignOf:
2599125137 case IrInstructionIdReturnAddress:
2599225138 case IrInstructionIdFrameAddress:
25993 case IrInstructionIdHandle:
25139 case IrInstructionIdFrameHandle:
25140 case IrInstructionIdFrameType:
25141 case IrInstructionIdFrameSizeSrc:
25142 case IrInstructionIdFrameSizeGen:
2599425143 case IrInstructionIdTestErrSrc:
2599525144 case IrInstructionIdTestErrGen:
2599625145 case IrInstructionIdFnProto:
......@@ -26023,13 +25172,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2602325172 case IrInstructionIdTagType:
2602425173 case IrInstructionIdErrorReturnTrace:
2602525174 case IrInstructionIdErrorUnion:
26026 case IrInstructionIdGetImplicitAllocator:
26027 case IrInstructionIdCoroAlloc:
26028 case IrInstructionIdCoroSize:
26029 case IrInstructionIdCoroSuspend:
26030 case IrInstructionIdCoroFree:
26031 case IrInstructionIdCoroPromise:
26032 case IrInstructionIdPromiseResultType:
2603325175 case IrInstructionIdFloatOp:
2603425176 case IrInstructionIdMulAdd:
2603525177 case IrInstructionIdAtomicLoad:
......@@ -26046,7 +25188,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2604625188 case IrInstructionIdHasDecl:
2604725189 case IrInstructionIdAllocaSrc:
2604825190 case IrInstructionIdAllocaGen:
26049 case IrInstructionIdResultPtr:
25191 case IrInstructionIdSpillEnd:
2605025192 return false;
2605125193
2605225194 case IrInstructionIdAsm:
src/ir.hpp+2
......@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
2828 AstNode *source_node);
2929const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
3030
31void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text);
32
3133#endif
src/ir_print.cpp+109-224
......@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
6464 }
6565}
6666
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *instruction) {
6868 fprintf(irp->f, "return ");
69 if (return_instruction->value != nullptr) {
70 ir_print_other_instruction(irp, return_instruction->value);
71 }
69 ir_print_other_instruction(irp, instruction->operand);
7270}
7371
7472static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
......@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
257255
258256static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {
259257 if (call_instruction->is_async) {
260 fprintf(irp->f, "async");
261 if (call_instruction->async_allocator != nullptr) {
262 fprintf(irp->f, "<");
263 ir_print_other_instruction(irp, call_instruction->async_allocator);
264 fprintf(irp->f, ">");
265 }
266 fprintf(irp->f, " ");
258 fprintf(irp->f, "async ");
267259 }
268260 if (call_instruction->fn_entry) {
269261 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
......@@ -284,13 +276,7 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi
284276
285277static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {
286278 if (call_instruction->is_async) {
287 fprintf(irp->f, "async");
288 if (call_instruction->async_allocator != nullptr) {
289 fprintf(irp->f, "<");
290 ir_print_other_instruction(irp, call_instruction->async_allocator);
291 fprintf(irp->f, ">");
292 }
293 fprintf(irp->f, " ");
279 fprintf(irp->f, "async ");
294280 }
295281 if (call_instruction->fn_entry) {
296282 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
......@@ -477,20 +463,21 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
477463 ir_print_other_instruction(irp, instruction->child_type);
478464}
479465
480static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) {
481 fprintf(irp->f, "promise");
482 if (instruction->payload_type != nullptr) {
483 fprintf(irp->f, "->");
484 ir_print_other_instruction(irp, instruction->payload_type);
485 }
486}
487
488466static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
489467 const char *const_kw = instruction->is_const ? "const " : "";
490468 fprintf(irp->f, "[]%s", const_kw);
491469 ir_print_other_instruction(irp, instruction->child_type);
492470}
493471
472static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *instruction) {
473 if (instruction->payload_type == nullptr) {
474 fprintf(irp->f, "anyframe");
475 } else {
476 fprintf(irp->f, "anyframe->");
477 ir_print_other_instruction(irp, instruction->payload_type);
478 }
479}
480
494481static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {
495482 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));
496483}
......@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
926913 fprintf(irp->f, "@frameAddress()");
927914}
928915
929static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {
930 fprintf(irp->f, "@handle()");
916static void ir_print_handle(IrPrint *irp, IrInstructionFrameHandle *instruction) {
917 fprintf(irp->f, "@frame()");
918}
919
920static void ir_print_frame_type(IrPrint *irp, IrInstructionFrameType *instruction) {
921 fprintf(irp->f, "@Frame(");
922 ir_print_other_instruction(irp, instruction->fn);
923 fprintf(irp->f, ")");
924}
925
926static void ir_print_frame_size_src(IrPrint *irp, IrInstructionFrameSizeSrc *instruction) {
927 fprintf(irp->f, "@frameSize(");
928 ir_print_other_instruction(irp, instruction->fn);
929 fprintf(irp->f, ")");
930}
931
932static void ir_print_frame_size_gen(IrPrint *irp, IrInstructionFrameSizeGen *instruction) {
933 fprintf(irp->f, "@frameSize(");
934 ir_print_other_instruction(irp, instruction->fn);
935 fprintf(irp->f, ")");
931936}
932937
933938static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
......@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru
13221327 fprintf(irp->f, ")");
13231328}
13241329
1325static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) {
1326 fprintf(irp->f, "ResultPtr(");
1327 ir_print_result_loc(irp, instruction->result_loc);
1328 fprintf(irp->f, ",");
1329 ir_print_other_instruction(irp, instruction->result);
1330 fprintf(irp->f, ")");
1331}
1332
13331330static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
13341331 fprintf(irp->f, "@OpaqueType()");
13351332}
......@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
13911388 ir_print_other_instruction(irp, instruction->payload);
13921389}
13931390
1394static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
1395 fprintf(irp->f, "cancel ");
1396 ir_print_other_instruction(irp, instruction->target);
1397}
1398
1399static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplicitAllocator *instruction) {
1400 fprintf(irp->f, "@getImplicitAllocator(");
1401 switch (instruction->id) {
1402 case ImplicitAllocatorIdArg:
1403 fprintf(irp->f, "Arg");
1404 break;
1405 case ImplicitAllocatorIdLocalVar:
1406 fprintf(irp->f, "LocalVar");
1407 break;
1408 }
1409 fprintf(irp->f, ")");
1410}
1411
1412static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1413 fprintf(irp->f, "@coroId(");
1414 ir_print_other_instruction(irp, instruction->promise_ptr);
1415 fprintf(irp->f, ")");
1416}
1417
1418static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
1419 fprintf(irp->f, "@coroAlloc(");
1420 ir_print_other_instruction(irp, instruction->coro_id);
1421 fprintf(irp->f, ")");
1422}
1423
1424static void ir_print_coro_size(IrPrint *irp, IrInstructionCoroSize *instruction) {
1425 fprintf(irp->f, "@coroSize()");
1426}
1427
1428static void ir_print_coro_begin(IrPrint *irp, IrInstructionCoroBegin *instruction) {
1429 fprintf(irp->f, "@coroBegin(");
1430 ir_print_other_instruction(irp, instruction->coro_id);
1431 fprintf(irp->f, ",");
1432 ir_print_other_instruction(irp, instruction->coro_mem_ptr);
1433 fprintf(irp->f, ")");
1434}
1435
1436static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *instruction) {
1437 fprintf(irp->f, "@coroAllocFail(");
1438 ir_print_other_instruction(irp, instruction->err_val);
1439 fprintf(irp->f, ")");
1440}
1441
1442static void ir_print_coro_suspend(IrPrint *irp, IrInstructionCoroSuspend *instruction) {
1443 fprintf(irp->f, "@coroSuspend(");
1444 if (instruction->save_point != nullptr) {
1445 ir_print_other_instruction(irp, instruction->save_point);
1446 } else {
1447 fprintf(irp->f, "null");
1448 }
1449 fprintf(irp->f, ",");
1450 ir_print_other_instruction(irp, instruction->is_final);
1451 fprintf(irp->f, ")");
1452}
1453
1454static void ir_print_coro_end(IrPrint *irp, IrInstructionCoroEnd *instruction) {
1455 fprintf(irp->f, "@coroEnd()");
1456}
1457
1458static void ir_print_coro_free(IrPrint *irp, IrInstructionCoroFree *instruction) {
1459 fprintf(irp->f, "@coroFree(");
1460 ir_print_other_instruction(irp, instruction->coro_id);
1461 fprintf(irp->f, ",");
1462 ir_print_other_instruction(irp, instruction->coro_handle);
1463 fprintf(irp->f, ")");
1464}
1465
1466static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) {
1467 fprintf(irp->f, "@coroResume(");
1468 ir_print_other_instruction(irp, instruction->awaiter_handle);
1469 fprintf(irp->f, ")");
1470}
1471
1472static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction) {
1473 fprintf(irp->f, "@coroSave(");
1474 ir_print_other_instruction(irp, instruction->coro_handle);
1475 fprintf(irp->f, ")");
1476}
1477
1478static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1479 fprintf(irp->f, "@coroPromise(");
1480 ir_print_other_instruction(irp, instruction->coro_handle);
1481 fprintf(irp->f, ")");
1482}
1483
1484static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1485 fprintf(irp->f, "@PromiseResultType(");
1486 ir_print_other_instruction(irp, instruction->promise_type);
1487 fprintf(irp->f, ")");
1488}
1489
1490static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
1491 fprintf(irp->f, "@coroAllocHelper(");
1492 ir_print_other_instruction(irp, instruction->realloc_fn);
1493 fprintf(irp->f, ",");
1494 ir_print_other_instruction(irp, instruction->coro_size);
1495 fprintf(irp->f, ")");
1496}
1497
14981391static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
14991392 fprintf(irp->f, "@atomicRmw(");
15001393 if (instruction->operand_type != nullptr) {
......@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct
15391432 fprintf(irp->f, ")");
15401433}
15411434
1542static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
1543 fprintf(irp->f, "@awaitBookkeeping(");
1544 ir_print_other_instruction(irp, instruction->promise_result_type);
1545 fprintf(irp->f, ")");
1546}
1547
15481435static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
15491436 fprintf(irp->f, "@saveErrRetAddr()");
15501437}
......@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
15551442 fprintf(irp->f, ")");
15561443}
15571444
1558static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1559 fprintf(irp->f, "@mergeErrRetTraces(");
1560 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1561 fprintf(irp->f, ",");
1562 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1563 fprintf(irp->f, ",");
1564 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1565 fprintf(irp->f, ")");
1566}
1567
1568static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1569 fprintf(irp->f, "@markErrRetTracePtr(");
1570 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1571 fprintf(irp->f, ")");
1572}
1573
15741445static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
15751446
15761447 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
......@@ -1638,6 +1509,47 @@ static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInit
16381509 fprintf(irp->f, ")");
16391510}
16401511
1512static void ir_print_suspend_begin(IrPrint *irp, IrInstructionSuspendBegin *instruction) {
1513 fprintf(irp->f, "@suspendBegin()");
1514}
1515
1516static void ir_print_suspend_finish(IrPrint *irp, IrInstructionSuspendFinish *instruction) {
1517 fprintf(irp->f, "@suspendFinish()");
1518}
1519
1520static void ir_print_resume(IrPrint *irp, IrInstructionResume *instruction) {
1521 fprintf(irp->f, "resume ");
1522 ir_print_other_instruction(irp, instruction->frame);
1523}
1524
1525static void ir_print_await_src(IrPrint *irp, IrInstructionAwaitSrc *instruction) {
1526 fprintf(irp->f, "@await(");
1527 ir_print_other_instruction(irp, instruction->frame);
1528 fprintf(irp->f, ",");
1529 ir_print_result_loc(irp, instruction->result_loc);
1530 fprintf(irp->f, ")");
1531}
1532
1533static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction) {
1534 fprintf(irp->f, "@await(");
1535 ir_print_other_instruction(irp, instruction->frame);
1536 fprintf(irp->f, ",");
1537 ir_print_other_instruction(irp, instruction->result_loc);
1538 fprintf(irp->f, ")");
1539}
1540
1541static void ir_print_spill_begin(IrPrint *irp, IrInstructionSpillBegin *instruction) {
1542 fprintf(irp->f, "@spillBegin(");
1543 ir_print_other_instruction(irp, instruction->operand);
1544 fprintf(irp->f, ")");
1545}
1546
1547static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) {
1548 fprintf(irp->f, "@spillEnd(");
1549 ir_print_other_instruction(irp, &instruction->begin->base);
1550 fprintf(irp->f, ")");
1551}
1552
16411553static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16421554 ir_print_prefix(irp, instruction);
16431555 switch (instruction->id) {
......@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
17271639 case IrInstructionIdArrayType:
17281640 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
17291641 break;
1730 case IrInstructionIdPromiseType:
1731 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1732 break;
17331642 case IrInstructionIdSliceType:
17341643 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
17351644 break;
1645 case IrInstructionIdAnyFrameType:
1646 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
1647 break;
17361648 case IrInstructionIdGlobalAsm:
17371649 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);
17381650 break;
......@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
18861798 case IrInstructionIdFrameAddress:
18871799 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
18881800 break;
1889 case IrInstructionIdHandle:
1890 ir_print_handle(irp, (IrInstructionHandle *)instruction);
1801 case IrInstructionIdFrameHandle:
1802 ir_print_handle(irp, (IrInstructionFrameHandle *)instruction);
1803 break;
1804 case IrInstructionIdFrameType:
1805 ir_print_frame_type(irp, (IrInstructionFrameType *)instruction);
1806 break;
1807 case IrInstructionIdFrameSizeSrc:
1808 ir_print_frame_size_src(irp, (IrInstructionFrameSizeSrc *)instruction);
1809 break;
1810 case IrInstructionIdFrameSizeGen:
1811 ir_print_frame_size_gen(irp, (IrInstructionFrameSizeGen *)instruction);
18911812 break;
18921813 case IrInstructionIdAlignOf:
18931814 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
......@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20061927 case IrInstructionIdResetResult:
20071928 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);
20081929 break;
2009 case IrInstructionIdResultPtr:
2010 ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
2011 break;
20121930 case IrInstructionIdOpaqueType:
20131931 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
20141932 break;
......@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20301948 case IrInstructionIdErrorUnion:
20311949 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
20321950 break;
2033 case IrInstructionIdCancel:
2034 ir_print_cancel(irp, (IrInstructionCancel *)instruction);
2035 break;
2036 case IrInstructionIdGetImplicitAllocator:
2037 ir_print_get_implicit_allocator(irp, (IrInstructionGetImplicitAllocator *)instruction);
2038 break;
2039 case IrInstructionIdCoroId:
2040 ir_print_coro_id(irp, (IrInstructionCoroId *)instruction);
2041 break;
2042 case IrInstructionIdCoroAlloc:
2043 ir_print_coro_alloc(irp, (IrInstructionCoroAlloc *)instruction);
2044 break;
2045 case IrInstructionIdCoroSize:
2046 ir_print_coro_size(irp, (IrInstructionCoroSize *)instruction);
2047 break;
2048 case IrInstructionIdCoroBegin:
2049 ir_print_coro_begin(irp, (IrInstructionCoroBegin *)instruction);
2050 break;
2051 case IrInstructionIdCoroAllocFail:
2052 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);
2053 break;
2054 case IrInstructionIdCoroSuspend:
2055 ir_print_coro_suspend(irp, (IrInstructionCoroSuspend *)instruction);
2056 break;
2057 case IrInstructionIdCoroEnd:
2058 ir_print_coro_end(irp, (IrInstructionCoroEnd *)instruction);
2059 break;
2060 case IrInstructionIdCoroFree:
2061 ir_print_coro_free(irp, (IrInstructionCoroFree *)instruction);
2062 break;
2063 case IrInstructionIdCoroResume:
2064 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
2065 break;
2066 case IrInstructionIdCoroSave:
2067 ir_print_coro_save(irp, (IrInstructionCoroSave *)instruction);
2068 break;
2069 case IrInstructionIdCoroAllocHelper:
2070 ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction);
2071 break;
20721951 case IrInstructionIdAtomicRmw:
20731952 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
20741953 break;
2075 case IrInstructionIdCoroPromise:
2076 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
2077 break;
2078 case IrInstructionIdPromiseResultType:
2079 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
2080 break;
2081 case IrInstructionIdAwaitBookkeeping:
2082 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
2083 break;
20841954 case IrInstructionIdSaveErrRetAddr:
20851955 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
20861956 break;
20871957 case IrInstructionIdAddImplicitReturnType:
20881958 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
20891959 break;
2090 case IrInstructionIdMergeErrRetTraces:
2091 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
2092 break;
2093 case IrInstructionIdMarkErrRetTracePtr:
2094 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
2095 break;
20961960 case IrInstructionIdFloatOp:
20971961 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
20981962 break;
......@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
21472011 case IrInstructionIdUnionInitNamedField:
21482012 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);
21492013 break;
2014 case IrInstructionIdSuspendBegin:
2015 ir_print_suspend_begin(irp, (IrInstructionSuspendBegin *)instruction);
2016 break;
2017 case IrInstructionIdSuspendFinish:
2018 ir_print_suspend_finish(irp, (IrInstructionSuspendFinish *)instruction);
2019 break;
2020 case IrInstructionIdResume:
2021 ir_print_resume(irp, (IrInstructionResume *)instruction);
2022 break;
2023 case IrInstructionIdAwaitSrc:
2024 ir_print_await_src(irp, (IrInstructionAwaitSrc *)instruction);
2025 break;
2026 case IrInstructionIdAwaitGen:
2027 ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction);
2028 break;
2029 case IrInstructionIdSpillBegin:
2030 ir_print_spill_begin(irp, (IrInstructionSpillBegin *)instruction);
2031 break;
2032 case IrInstructionIdSpillEnd:
2033 ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction);
2034 break;
21502035 }
21512036 fprintf(irp->f, "\n");
21522037}
src/parser.cpp+11-35
......@@ -282,8 +282,8 @@ static AstNode *ast_parse_prefix_op_expr(
282282 case NodeTypeAwaitExpr:
283283 right = &prefix->data.await_expr.expr;
284284 break;
285 case NodeTypePromiseType:
286 right = &prefix->data.promise_type.payload_type;
285 case NodeTypeAnyFrameType:
286 right = &prefix->data.anyframe_type.payload_type;
287287 break;
288288 case NodeTypeArrayType:
289289 right = &prefix->data.array_type.child_type;
......@@ -1167,7 +1167,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
11671167// <- AsmExpr
11681168// / IfExpr
11691169// / KEYWORD_break BreakLabel? Expr?
1170// / KEYWORD_cancel Expr
11711170// / KEYWORD_comptime Expr
11721171// / KEYWORD_continue BreakLabel?
11731172// / KEYWORD_resume Expr
......@@ -1195,14 +1194,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
11951194 return res;
11961195 }
11971196
1198 Token *cancel = eat_token_if(pc, TokenIdKeywordCancel);
1199 if (cancel != nullptr) {
1200 AstNode *expr = ast_expect(pc, ast_parse_expr);
1201 AstNode *res = ast_create_node(pc, NodeTypeCancel, cancel);
1202 res->data.cancel_expr.expr = expr;
1203 return res;
1204 }
1205
12061197 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);
12071198 if (comptime != nullptr) {
12081199 AstNode *expr = ast_expect(pc, ast_parse_expr);
......@@ -1643,9 +1634,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
16431634 if (null != nullptr)
16441635 return ast_create_node(pc, NodeTypeNullLiteral, null);
16451636
1646 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);
1647 if (promise != nullptr)
1648 return ast_create_node(pc, NodeTypePromiseType, promise);
1637 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
1638 if (anyframe != nullptr)
1639 return ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
16491640
16501641 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);
16511642 if (true_token != nullptr) {
......@@ -2042,11 +2033,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
20422033 }
20432034 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {
20442035 res.cc = CallingConventionAsync;
2045 if (eat_token_if(pc, TokenIdCmpLessThan) == nullptr)
2046 return Optional<AstNodeFnProto>::some(res);
2047
2048 res.async_allocator_type = ast_expect(pc, ast_parse_type_expr);
2049 expect_token(pc, TokenIdCmpGreaterThan);
20502036 return Optional<AstNodeFnProto>::some(res);
20512037 }
20522038
......@@ -2522,7 +2508,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
25222508
25232509// PrefixTypeOp
25242510// <- QUESTIONMARK
2525// / KEYWORD_promise MINUSRARROW
2511// / KEYWORD_anyframe MINUSRARROW
25262512// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
25272513// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
25282514static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
......@@ -2533,10 +2519,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
25332519 return res;
25342520 }
25352521
2536 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);
2537 if (promise != nullptr) {
2522 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
2523 if (anyframe != nullptr) {
25382524 if (eat_token_if(pc, TokenIdArrow) != nullptr) {
2539 AstNode *res = ast_create_node(pc, NodeTypePromiseType, promise);
2525 AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
25402526 return res;
25412527 }
25422528
......@@ -2680,11 +2666,6 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
26802666 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
26812667 res->data.fn_call_expr.is_async = true;
26822668 res->data.fn_call_expr.seen = false;
2683 if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) {
2684 AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr);
2685 expect_token(pc, TokenIdCmpGreaterThan);
2686 res->data.fn_call_expr.async_allocator = prefix_expr;
2687 }
26882669
26892670 return res;
26902671}
......@@ -2858,7 +2839,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
28582839 visit_node_list(&node->data.fn_proto.params, visit, context);
28592840 visit_field(&node->data.fn_proto.align_expr, visit, context);
28602841 visit_field(&node->data.fn_proto.section_expr, visit, context);
2861 visit_field(&node->data.fn_proto.async_allocator_type, visit, context);
28622842 break;
28632843 case NodeTypeFnDef:
28642844 visit_field(&node->data.fn_def.fn_proto, visit, context);
......@@ -2918,7 +2898,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29182898 case NodeTypeFnCallExpr:
29192899 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
29202900 visit_node_list(&node->data.fn_call_expr.params, visit, context);
2921 visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
29222901 break;
29232902 case NodeTypeArrayAccessExpr:
29242903 visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);
......@@ -3034,8 +3013,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30343013 case NodeTypeInferredArrayType:
30353014 visit_field(&node->data.array_type.child_type, visit, context);
30363015 break;
3037 case NodeTypePromiseType:
3038 visit_field(&node->data.promise_type.payload_type, visit, context);
3016 case NodeTypeAnyFrameType:
3017 visit_field(&node->data.anyframe_type.payload_type, visit, context);
30393018 break;
30403019 case NodeTypeErrorType:
30413020 // none
......@@ -3047,9 +3026,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30473026 case NodeTypeErrorSetDecl:
30483027 visit_node_list(&node->data.err_set_decl.decls, visit, context);
30493028 break;
3050 case NodeTypeCancel:
3051 visit_field(&node->data.cancel_expr.expr, visit, context);
3052 break;
30533029 case NodeTypeResume:
30543030 visit_field(&node->data.resume_expr.expr, visit, context);
30553031 break;
src/target.cpp+4
......@@ -1759,3 +1759,7 @@ bool target_supports_libunwind(const ZigTarget *target) {
17591759 return true;
17601760}
17611761
1762
1763unsigned target_fn_align(const ZigTarget *target) {
1764 return 16;
1765}
src/target.hpp+2
......@@ -197,4 +197,6 @@ uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
197197size_t target_libc_count(void);
198198void target_libc_enum(size_t index, ZigTarget *out_target);
199199
200unsigned target_fn_align(const ZigTarget *target);
201
200202#endif
src/tokenizer.cpp+2-4
......@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {
109109 {"align", TokenIdKeywordAlign},
110110 {"allowzero", TokenIdKeywordAllowZero},
111111 {"and", TokenIdKeywordAnd},
112 {"anyframe", TokenIdKeywordAnyFrame},
112113 {"asm", TokenIdKeywordAsm},
113114 {"async", TokenIdKeywordAsync},
114115 {"await", TokenIdKeywordAwait},
115116 {"break", TokenIdKeywordBreak},
116 {"cancel", TokenIdKeywordCancel},
117117 {"catch", TokenIdKeywordCatch},
118118 {"comptime", TokenIdKeywordCompTime},
119119 {"const", TokenIdKeywordConst},
......@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {
136136 {"or", TokenIdKeywordOr},
137137 {"orelse", TokenIdKeywordOrElse},
138138 {"packed", TokenIdKeywordPacked},
139 {"promise", TokenIdKeywordPromise},
140139 {"pub", TokenIdKeywordPub},
141140 {"resume", TokenIdKeywordResume},
142141 {"return", TokenIdKeywordReturn},
......@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {
15311530 case TokenIdKeywordAwait: return "await";
15321531 case TokenIdKeywordResume: return "resume";
15331532 case TokenIdKeywordSuspend: return "suspend";
1534 case TokenIdKeywordCancel: return "cancel";
15351533 case TokenIdKeywordAlign: return "align";
15361534 case TokenIdKeywordAnd: return "and";
1535 case TokenIdKeywordAnyFrame: return "anyframe";
15371536 case TokenIdKeywordAsm: return "asm";
15381537 case TokenIdKeywordBreak: return "break";
15391538 case TokenIdKeywordCatch: return "catch";
......@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {
15581557 case TokenIdKeywordOr: return "or";
15591558 case TokenIdKeywordOrElse: return "orelse";
15601559 case TokenIdKeywordPacked: return "packed";
1561 case TokenIdKeywordPromise: return "promise";
15621560 case TokenIdKeywordPub: return "pub";
15631561 case TokenIdKeywordReturn: return "return";
15641562 case TokenIdKeywordLinkSection: return "linksection";
src/tokenizer.hpp+1-2
......@@ -53,11 +53,11 @@ enum TokenId {
5353 TokenIdKeywordAlign,
5454 TokenIdKeywordAllowZero,
5555 TokenIdKeywordAnd,
56 TokenIdKeywordAnyFrame,
5657 TokenIdKeywordAsm,
5758 TokenIdKeywordAsync,
5859 TokenIdKeywordAwait,
5960 TokenIdKeywordBreak,
60 TokenIdKeywordCancel,
6161 TokenIdKeywordCatch,
6262 TokenIdKeywordCompTime,
6363 TokenIdKeywordConst,
......@@ -81,7 +81,6 @@ enum TokenId {
8181 TokenIdKeywordOr,
8282 TokenIdKeywordOrElse,
8383 TokenIdKeywordPacked,
84 TokenIdKeywordPromise,
8584 TokenIdKeywordPub,
8685 TokenIdKeywordResume,
8786 TokenIdKeywordReturn,
src/zig_llvm.cpp+8-3
......@@ -42,7 +42,6 @@
4242#include <llvm/Support/TargetRegistry.h>
4343#include <llvm/Target/TargetMachine.h>
4444#include <llvm/Target/CodeGenCWrappers.h>
45#include <llvm/Transforms/Coroutines.h>
4645#include <llvm/Transforms/IPO.h>
4746#include <llvm/Transforms/IPO/AlwaysInliner.h>
4847#include <llvm/Transforms/IPO/PassManagerBuilder.h>
......@@ -203,8 +202,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
203202 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
204203 }
205204
206 addCoroutinePassesToExtensionPoints(*PMBuilder);
207
208205 // Set up the per-function pass manager.
209206 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
210207 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
......@@ -898,6 +895,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
898895 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
899896}
900897
898void ZigLLVMSetTailCall(LLVMValueRef Call) {
899 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);
900}
901
902void ZigLLVMFunctionSetPrefixData(LLVMValueRef function, LLVMValueRef data) {
903 unwrap<Function>(function)->setPrefixData(unwrap<Constant>(data));
904}
905
901906
902907class MyOStream: public raw_ostream {
903908 public:
src/zig_llvm.h+2
......@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde
211211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
212212
213213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
214ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call);
215ZIG_EXTERN_C void ZigLLVMFunctionSetPrefixData(LLVMValueRef fn, LLVMValueRef data);
214216
215217ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
216218ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
std/event/channel.zig+45-72
......@@ -2,8 +2,6 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const Loop = std.event.Loop;
86
97/// many producer, many consumer, thread-safe, runtime configurable buffer size
......@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {
7775 /// must be called when all calls to put and get have suspended and no more calls occur
7876 pub fn destroy(self: *SelfChannel) void {
7977 while (self.getters.get()) |get_node| {
80 cancel get_node.data.tick_node.data;
78 resume get_node.data.tick_node.data;
8179 }
8280 while (self.putters.get()) |put_node| {
83 cancel put_node.data.tick_node.data;
81 resume put_node.data.tick_node.data;
8482 }
8583 self.loop.allocator.free(self.buffer_nodes);
8684 self.loop.allocator.destroy(self);
8785 }
8886
89 /// puts a data item in the channel. The promise completes when the value has been added to the
87 /// puts a data item in the channel. The function returns when the value has been added to the
9088 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
91 pub async fn put(self: *SelfChannel, data: T) void {
92 // TODO fix this workaround
93 suspend {
94 resume @handle();
95 }
96
97 var my_tick_node = Loop.NextTickNode.init(@handle());
89 /// Or when the channel is destroyed.
90 pub fn put(self: *SelfChannel, data: T) void {
91 var my_tick_node = Loop.NextTickNode.init(@frame());
9892 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{
9993 .tick_node = &my_tick_node,
10094 .data = data,
......@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {
10296
10397 // TODO test canceling a put()
10498 errdefer {
105 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
99 _ = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
106100 const need_dispatch = !self.putters.remove(&queue_node);
107101 self.loop.cancelOnNextTick(&my_tick_node);
108102 if (need_dispatch) {
109103 // oops we made the put_count incorrect for a period of time. fix by dispatching.
110 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
104 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
111105 self.dispatch();
112106 }
113107 }
114108 suspend {
115109 self.putters.put(&queue_node);
116 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
110 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
117111
118112 self.dispatch();
119113 }
120114 }
121115
122 /// await this function to get an item from the channel. If the buffer is empty, the promise will
116 /// await this function to get an item from the channel. If the buffer is empty, the frame will
123117 /// complete when the next item is put in the channel.
124118 pub async fn get(self: *SelfChannel) T {
125 // TODO fix this workaround
126 suspend {
127 resume @handle();
128 }
129
130 // TODO integrate this function with named return values
131 // so we can get rid of this extra result copy
119 // TODO https://github.com/ziglang/zig/issues/2765
132120 var result: T = undefined;
133 var my_tick_node = Loop.NextTickNode.init(@handle());
121 var my_tick_node = Loop.NextTickNode.init(@frame());
134122 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
135123 .tick_node = &my_tick_node,
136124 .data = GetNode.Data{
......@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {
140128
141129 // TODO test canceling a get()
142130 errdefer {
143 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
131 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
144132 const need_dispatch = !self.getters.remove(&queue_node);
145133 self.loop.cancelOnNextTick(&my_tick_node);
146134 if (need_dispatch) {
147135 // oops we made the get_count incorrect for a period of time. fix by dispatching.
148 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
136 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
149137 self.dispatch();
150138 }
151139 }
152140
153141 suspend {
154142 self.getters.put(&queue_node);
155 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
143 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
156144
157145 self.dispatch();
158146 }
......@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {
173161 /// Await is necessary for locking purposes. The function will be resumed after checking the channel
174162 /// for data and will not wait for data to be available.
175163 pub async fn getOrNull(self: *SelfChannel) ?T {
176 // TODO fix this workaround
177 suspend {
178 resume @handle();
179 }
180
181164 // TODO integrate this function with named return values
182165 // so we can get rid of this extra result copy
183166 var result: ?T = null;
184 var my_tick_node = Loop.NextTickNode.init(@handle());
167 var my_tick_node = Loop.NextTickNode.init(@frame());
185168 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);
186169 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
187170 .tick_node = &my_tick_node,
......@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {
197180 // TODO test canceling getOrNull
198181 errdefer {
199182 _ = self.or_null_queue.remove(&or_null_node);
200 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
183 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
201184 const need_dispatch = !self.getters.remove(&queue_node);
202185 self.loop.cancelOnNextTick(&my_tick_node);
203186 if (need_dispatch) {
204187 // oops we made the get_count incorrect for a period of time. fix by dispatching.
205 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
188 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
206189 self.dispatch();
207190 }
208191 }
209192
210193 suspend {
211194 self.getters.put(&queue_node);
212 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
195 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
213196 self.or_null_queue.put(&or_null_node);
214197
215198 self.dispatch();
......@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {
219202
220203 fn dispatch(self: *SelfChannel) void {
221204 // set the "need dispatch" flag
222 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
205 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 1, .SeqCst);
223206
224207 lock: while (true) {
225208 // set the lock flag
226 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
209 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 1, .SeqCst);
227210 if (prev_lock != 0) return;
228211
229212 // clear the need_dispatch flag since we're about to do it
230 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
213 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
231214
232215 while (true) {
233216 one_dispatch: {
234217 // later we correct these extra subtractions
235 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
236 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
218 var get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
219 var put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
237220
238221 // transfer self.buffer to self.getters
239222 while (self.buffer_len != 0) {
......@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {
252235 self.loop.onNextTick(get_node.tick_node);
253236 self.buffer_len -= 1;
254237
255 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
238 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
256239 }
257240
258241 // direct transfer self.putters to self.getters
......@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {
272255 self.loop.onNextTick(get_node.tick_node);
273256 self.loop.onNextTick(put_node.tick_node);
274257
275 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
276 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
258 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
259 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
277260 }
278261
279262 // transfer self.putters to self.buffer
......@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {
285268 self.buffer_index +%= 1;
286269 self.buffer_len += 1;
287270
288 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
271 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
289272 }
290273 }
291274
292275 // undo the extra subtractions
293 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
294 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
276 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
277 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
295278
296279 // All the "get or null" functions should resume now.
297280 var remove_count: usize = 0;
......@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {
300283 self.loop.onNextTick(or_null_node.data.data.tick_node);
301284 }
302285 if (remove_count != 0) {
303 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, remove_count, AtomicOrder.SeqCst);
286 _ = @atomicRmw(usize, &self.get_count, .Sub, remove_count, .SeqCst);
304287 }
305288
306289 // clear need-dispatch flag
307 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
290 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
308291 if (need_dispatch != 0) continue;
309292
310 const my_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
293 const my_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 0, .SeqCst);
311294 assert(my_lock != 0);
312295
313296 // we have to check again now that we unlocked
314 if (@atomicLoad(u8, &self.need_dispatch, AtomicOrder.SeqCst) != 0) continue :lock;
297 if (@atomicLoad(u8, &self.need_dispatch, .SeqCst) != 0) continue :lock;
315298
316299 return;
317300 }
......@@ -324,51 +307,41 @@ test "std.event.Channel" {
324307 // https://github.com/ziglang/zig/issues/1908
325308 if (builtin.single_threaded) return error.SkipZigTest;
326309
327 const allocator = std.heap.direct_allocator;
328
329310 var loop: Loop = undefined;
330311 // TODO make a multi threaded test
331 try loop.initSingleThreaded(allocator);
312 try loop.initSingleThreaded(std.heap.direct_allocator);
332313 defer loop.deinit();
333314
334315 const channel = try Channel(i32).create(&loop, 0);
335316 defer channel.destroy();
336317
337 const handle = try async<allocator> testChannelGetter(&loop, channel);
338 defer cancel handle;
339
340 const putter = try async<allocator> testChannelPutter(channel);
341 defer cancel putter;
318 const handle = async testChannelGetter(&loop, channel);
319 const putter = async testChannelPutter(channel);
342320
343321 loop.run();
344322}
345323
346324async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
347 errdefer @panic("test failed");
348
349 const value1_promise = try async channel.get();
350 const value1 = await value1_promise;
325 const value1 = channel.get();
351326 testing.expect(value1 == 1234);
352327
353 const value2_promise = try async channel.get();
354 const value2 = await value2_promise;
328 const value2 = channel.get();
355329 testing.expect(value2 == 4567);
356330
357 const value3_promise = try async channel.getOrNull();
358 const value3 = await value3_promise;
331 const value3 = channel.getOrNull();
359332 testing.expect(value3 == null);
360333
361 const last_put = try async testPut(channel, 4444);
362 const value4 = await try async channel.getOrNull();
334 const last_put = async testPut(channel, 4444);
335 const value4 = channel.getOrNull();
363336 testing.expect(value4.? == 4444);
364337 await last_put;
365338}
366339
367340async fn testChannelPutter(channel: *Channel(i32)) void {
368 await (async channel.put(1234) catch @panic("out of memory"));
369 await (async channel.put(4567) catch @panic("out of memory"));
341 channel.put(1234);
342 channel.put(4567);
370343}
371344
372345async fn testPut(channel: *Channel(i32), value: i32) void {
373 await (async channel.put(value) catch @panic("out of memory"));
346 channel.put(value);
374347}
std/event/fs.zig+640-694
......@@ -76,17 +76,13 @@ pub const Request = struct {
7676
7777pub const PWriteVError = error{OutOfMemory} || File.WriteError;
7878
79/// data - just the inner references - must live until pwritev promise completes.
79/// data - just the inner references - must live until pwritev frame completes.
8080pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {
81 // workaround for https://github.com/ziglang/zig/issues/1194
82 suspend {
83 resume @handle();
84 }
8581 switch (builtin.os) {
86 builtin.Os.macosx,
87 builtin.Os.linux,
88 builtin.Os.freebsd,
89 builtin.Os.netbsd,
82 .macosx,
83 .linux,
84 .freebsd,
85 .netbsd,
9086 => {
9187 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
9288 defer loop.allocator.free(iovecs);
......@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
10096
10197 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);
10298 },
103 builtin.Os.windows => {
99 .windows => {
104100 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);
105101 defer loop.allocator.free(data_copy);
106102 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);
......@@ -109,7 +105,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
109105 }
110106}
111107
112/// data must outlive the returned promise
108/// data must outlive the returned frame
113109pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
114110 if (data.len == 0) return;
115111 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);
......@@ -123,15 +119,10 @@ pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, off
123119}
124120
125121pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {
126 // workaround for https://github.com/ziglang/zig/issues/1194
127 suspend {
128 resume @handle();
129 }
130
131122 var resume_node = Loop.ResumeNode.Basic{
132123 .base = Loop.ResumeNode{
133124 .id = Loop.ResumeNode.Id.Basic,
134 .handle = @handle(),
125 .handle = @frame(),
135126 .overlapped = windows.OVERLAPPED{
136127 .Internal = 0,
137128 .InternalHigh = 0,
......@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)
166157 }
167158}
168159
169/// iovecs must live until pwritev promise completes.
160/// iovecs must live until pwritev frame completes.
170161pub async fn pwritevPosix(
171162 loop: *Loop,
172163 fd: fd_t,
173164 iovecs: []const os.iovec_const,
174165 offset: usize,
175166) os.WriteError!void {
176 // workaround for https://github.com/ziglang/zig/issues/1194
177 suspend {
178 resume @handle();
179 }
180
181167 var req_node = RequestNode{
182168 .prev = null,
183169 .next = null,
......@@ -194,7 +180,7 @@ pub async fn pwritevPosix(
194180 .TickNode = Loop.NextTickNode{
195181 .prev = null,
196182 .next = null,
197 .data = @handle(),
183 .data = @frame(),
198184 },
199185 },
200186 },
......@@ -211,19 +197,14 @@ pub async fn pwritevPosix(
211197
212198pub const PReadVError = error{OutOfMemory} || File.ReadError;
213199
214/// data - just the inner references - must live until preadv promise completes.
200/// data - just the inner references - must live until preadv frame completes.
215201pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {
216 // workaround for https://github.com/ziglang/zig/issues/1194
217 suspend {
218 resume @handle();
219 }
220
221202 assert(data.len != 0);
222203 switch (builtin.os) {
223 builtin.Os.macosx,
224 builtin.Os.linux,
225 builtin.Os.freebsd,
226 builtin.Os.netbsd,
204 .macosx,
205 .linux,
206 .freebsd,
207 .netbsd,
227208 => {
228209 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229210 defer loop.allocator.free(iovecs);
......@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
237218
238219 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);
239220 },
240 builtin.Os.windows => {
221 .windows => {
241222 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);
242223 defer loop.allocator.free(data_copy);
243224 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);
......@@ -246,7 +227,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
246227 }
247228}
248229
249/// data must outlive the returned promise
230/// data must outlive the returned frame
250231pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
251232 assert(data.len != 0);
252233 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);
......@@ -272,15 +253,10 @@ pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u6
272253}
273254
274255pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {
275 // workaround for https://github.com/ziglang/zig/issues/1194
276 suspend {
277 resume @handle();
278 }
279
280256 var resume_node = Loop.ResumeNode.Basic{
281257 .base = Loop.ResumeNode{
282258 .id = Loop.ResumeNode.Id.Basic,
283 .handle = @handle(),
259 .handle = @frame(),
284260 .overlapped = windows.OVERLAPPED{
285261 .Internal = 0,
286262 .InternalHigh = 0,
......@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize
314290 return usize(bytes_transferred);
315291}
316292
317/// iovecs must live until preadv promise completes
293/// iovecs must live until preadv frame completes
318294pub async fn preadvPosix(
319295 loop: *Loop,
320296 fd: fd_t,
321297 iovecs: []const os.iovec,
322298 offset: usize,
323299) os.ReadError!usize {
324 // workaround for https://github.com/ziglang/zig/issues/1194
325 suspend {
326 resume @handle();
327 }
328
329300 var req_node = RequestNode{
330301 .prev = null,
331302 .next = null,
......@@ -342,7 +313,7 @@ pub async fn preadvPosix(
342313 .TickNode = Loop.NextTickNode{
343314 .prev = null,
344315 .next = null,
345 .data = @handle(),
316 .data = @frame(),
346317 },
347318 },
348319 },
......@@ -363,11 +334,6 @@ pub async fn openPosix(
363334 flags: u32,
364335 mode: File.Mode,
365336) File.OpenError!fd_t {
366 // workaround for https://github.com/ziglang/zig/issues/1194
367 suspend {
368 resume @handle();
369 }
370
371337 const path_c = try std.os.toPosixPath(path);
372338
373339 var req_node = RequestNode{
......@@ -386,7 +352,7 @@ pub async fn openPosix(
386352 .TickNode = Loop.NextTickNode{
387353 .prev = null,
388354 .next = null,
389 .data = @handle(),
355 .data = @frame(),
390356 },
391357 },
392358 },
......@@ -403,12 +369,12 @@ pub async fn openPosix(
403369
404370pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
405371 switch (builtin.os) {
406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
372 .macosx, .linux, .freebsd, .netbsd => {
407373 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
408374 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
409375 },
410376
411 builtin.Os.windows => return windows.CreateFile(
377 .windows => return windows.CreateFile(
412378 path,
413379 windows.GENERIC_READ,
414380 windows.FILE_SHARE_READ,
......@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
431397/// Creates if does not exist. Truncates the file if it exists.
432398pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
433399 switch (builtin.os) {
434 builtin.Os.macosx,
435 builtin.Os.linux,
436 builtin.Os.freebsd,
437 builtin.Os.netbsd,
400 .macosx,
401 .linux,
402 .freebsd,
403 .netbsd,
438404 => {
439405 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
440406 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
441407 },
442 builtin.Os.windows => return windows.CreateFile(
408 .windows => return windows.CreateFile(
443409 path,
444410 windows.GENERIC_WRITE,
445411 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
......@@ -459,12 +425,12 @@ pub async fn openReadWrite(
459425 mode: File.Mode,
460426) File.OpenError!fd_t {
461427 switch (builtin.os) {
462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
428 .macosx, .linux, .freebsd, .netbsd => {
463429 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
464430 return await (async openPosix(loop, path, flags, mode) catch unreachable);
465431 },
466432
467 builtin.Os.windows => return windows.CreateFile(
433 .windows => return windows.CreateFile(
468434 path,
469435 windows.GENERIC_WRITE | windows.GENERIC_READ,
470436 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
......@@ -489,9 +455,9 @@ pub const CloseOperation = struct {
489455 os_data: OsData,
490456
491457 const OsData = switch (builtin.os) {
492 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
458 .linux, .macosx, .freebsd, .netbsd => OsDataPosix,
493459
494 builtin.Os.windows => struct {
460 .windows => struct {
495461 handle: ?fd_t,
496462 },
497463
......@@ -508,8 +474,8 @@ pub const CloseOperation = struct {
508474 self.* = CloseOperation{
509475 .loop = loop,
510476 .os_data = switch (builtin.os) {
511 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),
512 builtin.Os.windows => OsData{ .handle = null },
477 .linux, .macosx, .freebsd, .netbsd => initOsDataPosix(self),
478 .windows => OsData{ .handle = null },
513479 else => @compileError("Unsupported OS"),
514480 },
515481 };
......@@ -535,10 +501,10 @@ pub const CloseOperation = struct {
535501 /// Defer this after creating.
536502 pub fn finish(self: *CloseOperation) void {
537503 switch (builtin.os) {
538 builtin.Os.linux,
539 builtin.Os.macosx,
540 builtin.Os.freebsd,
541 builtin.Os.netbsd,
504 .linux,
505 .macosx,
506 .freebsd,
507 .netbsd,
542508 => {
543509 if (self.os_data.have_fd) {
544510 self.loop.posixFsRequest(&self.os_data.close_req_node);
......@@ -546,7 +512,7 @@ pub const CloseOperation = struct {
546512 self.loop.allocator.destroy(self);
547513 }
548514 },
549 builtin.Os.windows => {
515 .windows => {
550516 if (self.os_data.handle) |handle| {
551517 os.close(handle);
552518 }
......@@ -558,15 +524,15 @@ pub const CloseOperation = struct {
558524
559525 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
560526 switch (builtin.os) {
561 builtin.Os.linux,
562 builtin.Os.macosx,
563 builtin.Os.freebsd,
564 builtin.Os.netbsd,
527 .linux,
528 .macosx,
529 .freebsd,
530 .netbsd,
565531 => {
566532 self.os_data.close_req_node.data.msg.Close.fd = handle;
567533 self.os_data.have_fd = true;
568534 },
569 builtin.Os.windows => {
535 .windows => {
570536 self.os_data.handle = handle;
571537 },
572538 else => @compileError("Unsupported OS"),
......@@ -576,14 +542,14 @@ pub const CloseOperation = struct {
576542 /// Undo a `setHandle`.
577543 pub fn clearHandle(self: *CloseOperation) void {
578544 switch (builtin.os) {
579 builtin.Os.linux,
580 builtin.Os.macosx,
581 builtin.Os.freebsd,
582 builtin.Os.netbsd,
545 .linux,
546 .macosx,
547 .freebsd,
548 .netbsd,
583549 => {
584550 self.os_data.have_fd = false;
585551 },
586 builtin.Os.windows => {
552 .windows => {
587553 self.os_data.handle = null;
588554 },
589555 else => @compileError("Unsupported OS"),
......@@ -592,15 +558,15 @@ pub const CloseOperation = struct {
592558
593559 pub fn getHandle(self: *CloseOperation) fd_t {
594560 switch (builtin.os) {
595 builtin.Os.linux,
596 builtin.Os.macosx,
597 builtin.Os.freebsd,
598 builtin.Os.netbsd,
561 .linux,
562 .macosx,
563 .freebsd,
564 .netbsd,
599565 => {
600566 assert(self.os_data.have_fd);
601567 return self.os_data.close_req_node.data.msg.Close.fd;
602568 },
603 builtin.Os.windows => {
569 .windows => {
604570 return self.os_data.handle.?;
605571 },
606572 else => @compileError("Unsupported OS"),
......@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi
617583/// contents must remain alive until writeFile completes.
618584pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
619585 switch (builtin.os) {
620 builtin.Os.linux,
621 builtin.Os.macosx,
622 builtin.Os.freebsd,
623 builtin.Os.netbsd,
586 .linux,
587 .macosx,
588 .freebsd,
589 .netbsd,
624590 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
625 builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
591 .windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
626592 else => @compileError("Unsupported OS"),
627593 }
628594}
......@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !
643609}
644610
645611async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
646 // workaround for https://github.com/ziglang/zig/issues/1194
647 suspend {
648 resume @handle();
649 }
650
651612 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);
652613 defer loop.allocator.free(path_with_null);
653614
......@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
667628 .TickNode = Loop.NextTickNode{
668629 .prev = null,
669630 .next = null,
670 .data = @handle(),
631 .data = @frame(),
671632 },
672633 },
673634 },
......@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
682643 return req_node.data.msg.WriteFile.result;
683644}
684645
685/// The promise resumes when the last data has been confirmed written, but before the file handle
646/// The frame resumes when the last data has been confirmed written, but before the file handle
686647/// is closed.
687648/// Caller owns returned memory.
688649pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {
......@@ -715,598 +676,583 @@ pub const WatchEventId = enum {
715676 Delete,
716677};
717678
718pub const WatchEventError = error{
719 UserResourceLimitReached,
720 SystemResources,
721 AccessDenied,
722 Unexpected, // TODO remove this possibility
723};
724
725pub fn Watch(comptime V: type) type {
726 return struct {
727 channel: *event.Channel(Event.Error!Event),
728 os_data: OsData,
729
730 const OsData = switch (builtin.os) {
731 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {
732 file_table: FileTable,
733 table_lock: event.Lock,
734
735 const FileTable = std.AutoHashMap([]const u8, *Put);
736 const Put = struct {
737 putter: promise,
738 value_ptr: *V,
739 };
740 },
741
742 builtin.Os.linux => LinuxOsData,
743 builtin.Os.windows => WindowsOsData,
744
745 else => @compileError("Unsupported OS"),
746 };
747
748 const WindowsOsData = struct {
749 table_lock: event.Lock,
750 dir_table: DirTable,
751 all_putters: std.atomic.Queue(promise),
752 ref_count: std.atomic.Int(usize),
753
754 const DirTable = std.AutoHashMap([]const u8, *Dir);
755 const FileTable = std.AutoHashMap([]const u16, V);
756
757 const Dir = struct {
758 putter: promise,
759 file_table: FileTable,
760 table_lock: event.Lock,
761 };
762 };
763
764 const LinuxOsData = struct {
765 putter: promise,
766 inotify_fd: i32,
767 wd_table: WdTable,
768 table_lock: event.Lock,
769
770 const WdTable = std.AutoHashMap(i32, Dir);
771 const FileTable = std.AutoHashMap([]const u8, V);
772
773 const Dir = struct {
774 dirname: []const u8,
775 file_table: FileTable,
776 };
777 };
778
779 const FileToHandle = std.AutoHashMap([]const u8, promise);
780
781 const Self = @This();
782
783 pub const Event = struct {
784 id: Id,
785 data: V,
786
787 pub const Id = WatchEventId;
788 pub const Error = WatchEventError;
789 };
790
791 pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
792 const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
793 errdefer channel.destroy();
794
795 switch (builtin.os) {
796 builtin.Os.linux => {
797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
798 errdefer os.close(inotify_fd);
799
800 var result: *Self = undefined;
801 _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
802 return result;
803 },
804
805 builtin.Os.windows => {
806 const self = try loop.allocator.create(Self);
807 errdefer loop.allocator.destroy(self);
808 self.* = Self{
809 .channel = channel,
810 .os_data = OsData{
811 .table_lock = event.Lock.init(loop),
812 .dir_table = OsData.DirTable.init(loop.allocator),
813 .ref_count = std.atomic.Int(usize).init(1),
814 .all_putters = std.atomic.Queue(promise).init(),
815 },
816 };
817 return self;
818 },
819
820 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
821 const self = try loop.allocator.create(Self);
822 errdefer loop.allocator.destroy(self);
823
824 self.* = Self{
825 .channel = channel,
826 .os_data = OsData{
827 .table_lock = event.Lock.init(loop),
828 .file_table = OsData.FileTable.init(loop.allocator),
829 },
830 };
831 return self;
832 },
833 else => @compileError("Unsupported OS"),
834 }
835 }
836
837 /// All addFile calls and removeFile calls must have completed.
838 pub fn destroy(self: *Self) void {
839 switch (builtin.os) {
840 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
841 // TODO we need to cancel the coroutines before destroying the lock
842 self.os_data.table_lock.deinit();
843 var it = self.os_data.file_table.iterator();
844 while (it.next()) |entry| {
845 cancel entry.value.putter;
846 self.channel.loop.allocator.free(entry.key);
847 }
848 self.channel.destroy();
849 },
850 builtin.Os.linux => cancel self.os_data.putter,
851 builtin.Os.windows => {
852 while (self.os_data.all_putters.get()) |putter_node| {
853 cancel putter_node.data;
854 }
855 self.deref();
856 },
857 else => @compileError("Unsupported OS"),
858 }
859 }
860
861 fn ref(self: *Self) void {
862 _ = self.os_data.ref_count.incr();
863 }
864
865 fn deref(self: *Self) void {
866 if (self.os_data.ref_count.decr() == 1) {
867 const allocator = self.channel.loop.allocator;
868 self.os_data.table_lock.deinit();
869 var it = self.os_data.dir_table.iterator();
870 while (it.next()) |entry| {
871 allocator.free(entry.key);
872 allocator.destroy(entry.value);
873 }
874 self.os_data.dir_table.deinit();
875 self.channel.destroy();
876 allocator.destroy(self);
877 }
878 }
879
880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
881 switch (builtin.os) {
882 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),
886 }
887 }
888
889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891 var resolved_path_consumed = false;
892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893
894 var close_op = try CloseOperation.start(self.channel.loop);
895 var close_op_consumed = false;
896 defer if (!close_op_consumed) close_op.finish();
897
898 const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
899 const mode = 0;
900 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
901 close_op.setHandle(fd);
902
903 var put_data: *OsData.Put = undefined;
904 const putter = try async self.kqPutEvents(close_op, value, &put_data);
905 close_op_consumed = true;
906 errdefer cancel putter;
907
908 const result = blk: {
909 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
910 defer held.release();
911
912 const gop = try self.os_data.file_table.getOrPut(resolved_path);
913 if (gop.found_existing) {
914 const prev_value = gop.kv.value.value_ptr.*;
915 cancel gop.kv.value.putter;
916 gop.kv.value = put_data;
917 break :blk prev_value;
918 } else {
919 resolved_path_consumed = true;
920 gop.kv.value = put_data;
921 break :blk null;
922 }
923 };
924
925 return result;
926 }
927
928 async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
929 // TODO https://github.com/ziglang/zig/issues/1194
930 suspend {
931 resume @handle();
932 }
933
934 var value_copy = value;
935 var put = OsData.Put{
936 .putter = @handle(),
937 .value_ptr = &value_copy,
938 };
939 out_put.* = &put;
940 self.channel.loop.beginOneEvent();
941
942 defer {
943 close_op.finish();
944 self.channel.loop.finishOneEvent();
945 }
946
947 while (true) {
948 if (await (async self.channel.loop.bsdWaitKev(
949 @intCast(usize, close_op.getHandle()),
950 os.EVFILT_VNODE,
951 os.NOTE_WRITE | os.NOTE_DELETE,
952 ) catch unreachable)) |kev| {
953 // TODO handle EV_ERROR
954 if (kev.fflags & os.NOTE_DELETE != 0) {
955 await (async self.channel.put(Self.Event{
956 .id = Event.Id.Delete,
957 .data = value_copy,
958 }) catch unreachable);
959 } else if (kev.fflags & os.NOTE_WRITE != 0) {
960 await (async self.channel.put(Self.Event{
961 .id = Event.Id.CloseWrite,
962 .data = value_copy,
963 }) catch unreachable);
964 }
965 } else |err| switch (err) {
966 error.EventNotFound => unreachable,
967 error.ProcessNotFound => unreachable,
968 error.Overflow => unreachable,
969 error.AccessDenied, error.SystemResources => |casted_err| {
970 await (async self.channel.put(casted_err) catch unreachable);
971 },
972 }
973 }
974 }
975
976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
977 const value_copy = value;
978
979 const dirname = std.fs.path.dirname(file_path) orelse ".";
980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
981 var dirname_with_null_consumed = false;
982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
983
984 const basename = std.fs.path.basename(file_path);
985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
986 var basename_with_null_consumed = false;
987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
988
989 const wd = try os.inotify_add_watchC(
990 self.os_data.inotify_fd,
991 dirname_with_null.ptr,
992 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
993 );
994 // wd is either a newly created watch or an existing one.
995
996 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
997 defer held.release();
998
999 const gop = try self.os_data.wd_table.getOrPut(wd);
1000 if (!gop.found_existing) {
1001 gop.kv.value = OsData.Dir{
1002 .dirname = dirname_with_null,
1003 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1004 };
1005 dirname_with_null_consumed = true;
1006 }
1007 const dir = &gop.kv.value;
1008
1009 const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
1010 if (file_table_gop.found_existing) {
1011 const prev_value = file_table_gop.kv.value;
1012 file_table_gop.kv.value = value_copy;
1013 return prev_value;
1014 } else {
1015 file_table_gop.kv.value = value_copy;
1016 basename_with_null_consumed = true;
1017 return null;
1018 }
1019 }
1020
1021 async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
1022 const value_copy = value;
1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
1024
1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1026 var dirname_consumed = false;
1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
1028
1029 const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
1030 defer self.channel.loop.allocator.free(dirname_utf16le);
1031
1032 // TODO https://github.com/ziglang/zig/issues/265
1033 const basename = std.fs.path.basename(file_path);
1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1035 var basename_utf16le_null_consumed = false;
1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
1038
1039 const dir_handle = try windows.CreateFileW(
1040 dirname_utf16le.ptr,
1041 windows.FILE_LIST_DIRECTORY,
1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
1043 null,
1044 windows.OPEN_EXISTING,
1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1046 null,
1047 );
1048 var dir_handle_consumed = false;
1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1050
1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1052 defer held.release();
1053
1054 const gop = try self.os_data.dir_table.getOrPut(dirname);
1055 if (gop.found_existing) {
1056 const dir = gop.kv.value;
1057 const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
1058 defer held_dir_lock.release();
1059
1060 const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1061 if (file_gop.found_existing) {
1062 const prev_value = file_gop.kv.value;
1063 file_gop.kv.value = value_copy;
1064 return prev_value;
1065 } else {
1066 file_gop.kv.value = value_copy;
1067 basename_utf16le_null_consumed = true;
1068 return null;
1069 }
1070 } else {
1071 errdefer _ = self.os_data.dir_table.remove(dirname);
1072 const dir = try self.channel.loop.allocator.create(OsData.Dir);
1073 errdefer self.channel.loop.allocator.destroy(dir);
1074
1075 dir.* = OsData.Dir{
1076 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1077 .table_lock = event.Lock.init(self.channel.loop),
1078 .putter = undefined,
1079 };
1080 gop.kv.value = dir;
1081 assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1082 basename_utf16le_null_consumed = true;
1083
1084 dir.putter = try async self.windowsDirReader(dir_handle, dir);
1085 dir_handle_consumed = true;
1086
1087 dirname_consumed = true;
1088
1089 return null;
1090 }
1091 }
1092
1093 async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1094 // TODO https://github.com/ziglang/zig/issues/1194
1095 suspend {
1096 resume @handle();
1097 }
1098
1099 self.ref();
1100 defer self.deref();
1101
1102 defer os.close(dir_handle);
1103
1104 var putter_node = std.atomic.Queue(promise).Node{
1105 .data = @handle(),
1106 .prev = null,
1107 .next = null,
1108 };
1109 self.os_data.all_putters.put(&putter_node);
1110 defer _ = self.os_data.all_putters.remove(&putter_node);
1111
1112 var resume_node = Loop.ResumeNode.Basic{
1113 .base = Loop.ResumeNode{
1114 .id = Loop.ResumeNode.Id.Basic,
1115 .handle = @handle(),
1116 .overlapped = windows.OVERLAPPED{
1117 .Internal = 0,
1118 .InternalHigh = 0,
1119 .Offset = 0,
1120 .OffsetHigh = 0,
1121 .hEvent = null,
1122 },
1123 },
1124 };
1125 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1126
1127 // TODO handle this error not in the channel but in the setup
1128 _ = windows.CreateIoCompletionPort(
1129 dir_handle,
1130 self.channel.loop.os_data.io_port,
1131 undefined,
1132 undefined,
1133 ) catch |err| {
1134 await (async self.channel.put(err) catch unreachable);
1135 return;
1136 };
1137
1138 while (true) {
1139 {
1140 // TODO only 1 beginOneEvent for the whole coroutine
1141 self.channel.loop.beginOneEvent();
1142 errdefer self.channel.loop.finishOneEvent();
1143 errdefer {
1144 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1145 }
1146 suspend {
1147 _ = windows.kernel32.ReadDirectoryChangesW(
1148 dir_handle,
1149 &event_buf,
1150 @intCast(windows.DWORD, event_buf.len),
1151 windows.FALSE, // watch subtree
1152 windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1153 windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1154 windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1155 windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1156 null, // number of bytes transferred (unused for async)
1157 &resume_node.base.overlapped,
1158 null, // completion routine - unused because we use IOCP
1159 );
1160 }
1161 }
1162 var bytes_transferred: windows.DWORD = undefined;
1163 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1164 const err = switch (windows.kernel32.GetLastError()) {
1165 else => |err| windows.unexpectedError(err),
1166 };
1167 await (async self.channel.put(err) catch unreachable);
1168 } else {
1169 // can't use @bytesToSlice because of the special variable length name field
1170 var ptr = event_buf[0..].ptr;
1171 const end_ptr = ptr + bytes_transferred;
1172 var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1173 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1174 ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1175 const emit = switch (ev.Action) {
1176 windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1177 windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1178 else => null,
1179 };
1180 if (emit) |id| {
1181 const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1182 const user_value = blk: {
1183 const held = await (async dir.table_lock.acquire() catch unreachable);
1184 defer held.release();
1185
1186 if (dir.file_table.get(basename_utf16le)) |entry| {
1187 break :blk entry.value;
1188 } else {
1189 break :blk null;
1190 }
1191 };
1192 if (user_value) |v| {
1193 await (async self.channel.put(Event{
1194 .id = id,
1195 .data = v,
1196 }) catch unreachable);
1197 }
1198 }
1199 if (ev.NextEntryOffset == 0) break;
1200 }
1201 }
1202 }
1203 }
1204
1205 pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1206 @panic("TODO");
1207 }
1208
1209 async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1210 // TODO https://github.com/ziglang/zig/issues/1194
1211 suspend {
1212 resume @handle();
1213 }
1214
1215 const loop = channel.loop;
1216
1217 var watch = Self{
1218 .channel = channel,
1219 .os_data = OsData{
1220 .putter = @handle(),
1221 .inotify_fd = inotify_fd,
1222 .wd_table = OsData.WdTable.init(loop.allocator),
1223 .table_lock = event.Lock.init(loop),
1224 },
1225 };
1226 out_watch.* = &watch;
1227
1228 loop.beginOneEvent();
1229
1230 defer {
1231 watch.os_data.table_lock.deinit();
1232 var wd_it = watch.os_data.wd_table.iterator();
1233 while (wd_it.next()) |wd_entry| {
1234 var file_it = wd_entry.value.file_table.iterator();
1235 while (file_it.next()) |file_entry| {
1236 loop.allocator.free(file_entry.key);
1237 }
1238 loop.allocator.free(wd_entry.value.dirname);
1239 }
1240 loop.finishOneEvent();
1241 os.close(inotify_fd);
1242 channel.destroy();
1243 }
1244
1245 var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1246
1247 while (true) {
1248 const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1249 const errno = os.linux.getErrno(rc);
1250 switch (errno) {
1251 0 => {
1252 // can't use @bytesToSlice because of the special variable length name field
1253 var ptr = event_buf[0..].ptr;
1254 const end_ptr = ptr + event_buf.len;
1255 var ev: *os.linux.inotify_event = undefined;
1256 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1257 ev = @ptrCast(*os.linux.inotify_event, ptr);
1258 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1259 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1260 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1261 const user_value = blk: {
1262 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1263 defer held.release();
1264
1265 const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1266 if (dir.file_table.get(basename_with_null)) |entry| {
1267 break :blk entry.value;
1268 } else {
1269 break :blk null;
1270 }
1271 };
1272 if (user_value) |v| {
1273 await (async channel.put(Event{
1274 .id = WatchEventId.CloseWrite,
1275 .data = v,
1276 }) catch unreachable);
1277 }
1278 }
1279 }
1280 },
1281 os.linux.EINTR => continue,
1282 os.linux.EINVAL => unreachable,
1283 os.linux.EFAULT => unreachable,
1284 os.linux.EAGAIN => {
1285 (await (async loop.linuxWaitFd(
1286 inotify_fd,
1287 os.linux.EPOLLET | os.linux.EPOLLIN,
1288 ) catch unreachable)) catch |err| {
1289 const transformed_err = switch (err) {
1290 error.FileDescriptorAlreadyPresentInSet => unreachable,
1291 error.OperationCausesCircularLoop => unreachable,
1292 error.FileDescriptorNotRegistered => unreachable,
1293 error.FileDescriptorIncompatibleWithEpoll => unreachable,
1294 error.Unexpected => unreachable,
1295 else => |e| e,
1296 };
1297 await (async channel.put(transformed_err) catch unreachable);
1298 };
1299 },
1300 else => unreachable,
1301 }
1302 }
1303 }
1304 };
1305}
679//pub const WatchEventError = error{
680// UserResourceLimitReached,
681// SystemResources,
682// AccessDenied,
683// Unexpected, // TODO remove this possibility
684//};
685//
686//pub fn Watch(comptime V: type) type {
687// return struct {
688// channel: *event.Channel(Event.Error!Event),
689// os_data: OsData,
690//
691// const OsData = switch (builtin.os) {
692// .macosx, .freebsd, .netbsd => struct {
693// file_table: FileTable,
694// table_lock: event.Lock,
695//
696// const FileTable = std.AutoHashMap([]const u8, *Put);
697// const Put = struct {
698// putter: anyframe,
699// value_ptr: *V,
700// };
701// },
702//
703// .linux => LinuxOsData,
704// .windows => WindowsOsData,
705//
706// else => @compileError("Unsupported OS"),
707// };
708//
709// const WindowsOsData = struct {
710// table_lock: event.Lock,
711// dir_table: DirTable,
712// all_putters: std.atomic.Queue(anyframe),
713// ref_count: std.atomic.Int(usize),
714//
715// const DirTable = std.AutoHashMap([]const u8, *Dir);
716// const FileTable = std.AutoHashMap([]const u16, V);
717//
718// const Dir = struct {
719// putter: anyframe,
720// file_table: FileTable,
721// table_lock: event.Lock,
722// };
723// };
724//
725// const LinuxOsData = struct {
726// putter: anyframe,
727// inotify_fd: i32,
728// wd_table: WdTable,
729// table_lock: event.Lock,
730//
731// const WdTable = std.AutoHashMap(i32, Dir);
732// const FileTable = std.AutoHashMap([]const u8, V);
733//
734// const Dir = struct {
735// dirname: []const u8,
736// file_table: FileTable,
737// };
738// };
739//
740// const FileToHandle = std.AutoHashMap([]const u8, anyframe);
741//
742// const Self = @This();
743//
744// pub const Event = struct {
745// id: Id,
746// data: V,
747//
748// pub const Id = WatchEventId;
749// pub const Error = WatchEventError;
750// };
751//
752// pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
753// const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
754// errdefer channel.destroy();
755//
756// switch (builtin.os) {
757// .linux => {
758// const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
759// errdefer os.close(inotify_fd);
760//
761// var result: *Self = undefined;
762// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
763// return result;
764// },
765//
766// .windows => {
767// const self = try loop.allocator.create(Self);
768// errdefer loop.allocator.destroy(self);
769// self.* = Self{
770// .channel = channel,
771// .os_data = OsData{
772// .table_lock = event.Lock.init(loop),
773// .dir_table = OsData.DirTable.init(loop.allocator),
774// .ref_count = std.atomic.Int(usize).init(1),
775// .all_putters = std.atomic.Queue(anyframe).init(),
776// },
777// };
778// return self;
779// },
780//
781// .macosx, .freebsd, .netbsd => {
782// const self = try loop.allocator.create(Self);
783// errdefer loop.allocator.destroy(self);
784//
785// self.* = Self{
786// .channel = channel,
787// .os_data = OsData{
788// .table_lock = event.Lock.init(loop),
789// .file_table = OsData.FileTable.init(loop.allocator),
790// },
791// };
792// return self;
793// },
794// else => @compileError("Unsupported OS"),
795// }
796// }
797//
798// /// All addFile calls and removeFile calls must have completed.
799// pub fn destroy(self: *Self) void {
800// switch (builtin.os) {
801// .macosx, .freebsd, .netbsd => {
802// // TODO we need to cancel the frames before destroying the lock
803// self.os_data.table_lock.deinit();
804// var it = self.os_data.file_table.iterator();
805// while (it.next()) |entry| {
806// cancel entry.value.putter;
807// self.channel.loop.allocator.free(entry.key);
808// }
809// self.channel.destroy();
810// },
811// .linux => cancel self.os_data.putter,
812// .windows => {
813// while (self.os_data.all_putters.get()) |putter_node| {
814// cancel putter_node.data;
815// }
816// self.deref();
817// },
818// else => @compileError("Unsupported OS"),
819// }
820// }
821//
822// fn ref(self: *Self) void {
823// _ = self.os_data.ref_count.incr();
824// }
825//
826// fn deref(self: *Self) void {
827// if (self.os_data.ref_count.decr() == 1) {
828// const allocator = self.channel.loop.allocator;
829// self.os_data.table_lock.deinit();
830// var it = self.os_data.dir_table.iterator();
831// while (it.next()) |entry| {
832// allocator.free(entry.key);
833// allocator.destroy(entry.value);
834// }
835// self.os_data.dir_table.deinit();
836// self.channel.destroy();
837// allocator.destroy(self);
838// }
839// }
840//
841// pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
842// switch (builtin.os) {
843// .macosx, .freebsd, .netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
844// .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
845// .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
846// else => @compileError("Unsupported OS"),
847// }
848// }
849//
850// async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
851// const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
852// var resolved_path_consumed = false;
853// defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
854//
855// var close_op = try CloseOperation.start(self.channel.loop);
856// var close_op_consumed = false;
857// defer if (!close_op_consumed) close_op.finish();
858//
859// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
860// const mode = 0;
861// const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
862// close_op.setHandle(fd);
863//
864// var put_data: *OsData.Put = undefined;
865// const putter = try async self.kqPutEvents(close_op, value, &put_data);
866// close_op_consumed = true;
867// errdefer cancel putter;
868//
869// const result = blk: {
870// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
871// defer held.release();
872//
873// const gop = try self.os_data.file_table.getOrPut(resolved_path);
874// if (gop.found_existing) {
875// const prev_value = gop.kv.value.value_ptr.*;
876// cancel gop.kv.value.putter;
877// gop.kv.value = put_data;
878// break :blk prev_value;
879// } else {
880// resolved_path_consumed = true;
881// gop.kv.value = put_data;
882// break :blk null;
883// }
884// };
885//
886// return result;
887// }
888//
889// async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
890// var value_copy = value;
891// var put = OsData.Put{
892// .putter = @frame(),
893// .value_ptr = &value_copy,
894// };
895// out_put.* = &put;
896// self.channel.loop.beginOneEvent();
897//
898// defer {
899// close_op.finish();
900// self.channel.loop.finishOneEvent();
901// }
902//
903// while (true) {
904// if (await (async self.channel.loop.bsdWaitKev(
905// @intCast(usize, close_op.getHandle()),
906// os.EVFILT_VNODE,
907// os.NOTE_WRITE | os.NOTE_DELETE,
908// ) catch unreachable)) |kev| {
909// // TODO handle EV_ERROR
910// if (kev.fflags & os.NOTE_DELETE != 0) {
911// await (async self.channel.put(Self.Event{
912// .id = Event.Id.Delete,
913// .data = value_copy,
914// }) catch unreachable);
915// } else if (kev.fflags & os.NOTE_WRITE != 0) {
916// await (async self.channel.put(Self.Event{
917// .id = Event.Id.CloseWrite,
918// .data = value_copy,
919// }) catch unreachable);
920// }
921// } else |err| switch (err) {
922// error.EventNotFound => unreachable,
923// error.ProcessNotFound => unreachable,
924// error.Overflow => unreachable,
925// error.AccessDenied, error.SystemResources => |casted_err| {
926// await (async self.channel.put(casted_err) catch unreachable);
927// },
928// }
929// }
930// }
931//
932// async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
933// const value_copy = value;
934//
935// const dirname = std.fs.path.dirname(file_path) orelse ".";
936// const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
937// var dirname_with_null_consumed = false;
938// defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
939//
940// const basename = std.fs.path.basename(file_path);
941// const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
942// var basename_with_null_consumed = false;
943// defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
944//
945// const wd = try os.inotify_add_watchC(
946// self.os_data.inotify_fd,
947// dirname_with_null.ptr,
948// os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
949// );
950// // wd is either a newly created watch or an existing one.
951//
952// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
953// defer held.release();
954//
955// const gop = try self.os_data.wd_table.getOrPut(wd);
956// if (!gop.found_existing) {
957// gop.kv.value = OsData.Dir{
958// .dirname = dirname_with_null,
959// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
960// };
961// dirname_with_null_consumed = true;
962// }
963// const dir = &gop.kv.value;
964//
965// const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
966// if (file_table_gop.found_existing) {
967// const prev_value = file_table_gop.kv.value;
968// file_table_gop.kv.value = value_copy;
969// return prev_value;
970// } else {
971// file_table_gop.kv.value = value_copy;
972// basename_with_null_consumed = true;
973// return null;
974// }
975// }
976//
977// async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
978// const value_copy = value;
979// // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
980//
981// const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
982// var dirname_consumed = false;
983// defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
984//
985// const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
986// defer self.channel.loop.allocator.free(dirname_utf16le);
987//
988// // TODO https://github.com/ziglang/zig/issues/265
989// const basename = std.fs.path.basename(file_path);
990// const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
991// var basename_utf16le_null_consumed = false;
992// defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
993// const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
994//
995// const dir_handle = try windows.CreateFileW(
996// dirname_utf16le.ptr,
997// windows.FILE_LIST_DIRECTORY,
998// windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
999// null,
1000// windows.OPEN_EXISTING,
1001// windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1002// null,
1003// );
1004// var dir_handle_consumed = false;
1005// defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1006//
1007// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1008// defer held.release();
1009//
1010// const gop = try self.os_data.dir_table.getOrPut(dirname);
1011// if (gop.found_existing) {
1012// const dir = gop.kv.value;
1013// const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
1014// defer held_dir_lock.release();
1015//
1016// const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1017// if (file_gop.found_existing) {
1018// const prev_value = file_gop.kv.value;
1019// file_gop.kv.value = value_copy;
1020// return prev_value;
1021// } else {
1022// file_gop.kv.value = value_copy;
1023// basename_utf16le_null_consumed = true;
1024// return null;
1025// }
1026// } else {
1027// errdefer _ = self.os_data.dir_table.remove(dirname);
1028// const dir = try self.channel.loop.allocator.create(OsData.Dir);
1029// errdefer self.channel.loop.allocator.destroy(dir);
1030//
1031// dir.* = OsData.Dir{
1032// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1033// .table_lock = event.Lock.init(self.channel.loop),
1034// .putter = undefined,
1035// };
1036// gop.kv.value = dir;
1037// assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1038// basename_utf16le_null_consumed = true;
1039//
1040// dir.putter = try async self.windowsDirReader(dir_handle, dir);
1041// dir_handle_consumed = true;
1042//
1043// dirname_consumed = true;
1044//
1045// return null;
1046// }
1047// }
1048//
1049// async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1050// self.ref();
1051// defer self.deref();
1052//
1053// defer os.close(dir_handle);
1054//
1055// var putter_node = std.atomic.Queue(anyframe).Node{
1056// .data = @frame(),
1057// .prev = null,
1058// .next = null,
1059// };
1060// self.os_data.all_putters.put(&putter_node);
1061// defer _ = self.os_data.all_putters.remove(&putter_node);
1062//
1063// var resume_node = Loop.ResumeNode.Basic{
1064// .base = Loop.ResumeNode{
1065// .id = Loop.ResumeNode.Id.Basic,
1066// .handle = @frame(),
1067// .overlapped = windows.OVERLAPPED{
1068// .Internal = 0,
1069// .InternalHigh = 0,
1070// .Offset = 0,
1071// .OffsetHigh = 0,
1072// .hEvent = null,
1073// },
1074// },
1075// };
1076// var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1077//
1078// // TODO handle this error not in the channel but in the setup
1079// _ = windows.CreateIoCompletionPort(
1080// dir_handle,
1081// self.channel.loop.os_data.io_port,
1082// undefined,
1083// undefined,
1084// ) catch |err| {
1085// await (async self.channel.put(err) catch unreachable);
1086// return;
1087// };
1088//
1089// while (true) {
1090// {
1091// // TODO only 1 beginOneEvent for the whole function
1092// self.channel.loop.beginOneEvent();
1093// errdefer self.channel.loop.finishOneEvent();
1094// errdefer {
1095// _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1096// }
1097// suspend {
1098// _ = windows.kernel32.ReadDirectoryChangesW(
1099// dir_handle,
1100// &event_buf,
1101// @intCast(windows.DWORD, event_buf.len),
1102// windows.FALSE, // watch subtree
1103// windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1104// windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1105// windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1106// windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1107// null, // number of bytes transferred (unused for async)
1108// &resume_node.base.overlapped,
1109// null, // completion routine - unused because we use IOCP
1110// );
1111// }
1112// }
1113// var bytes_transferred: windows.DWORD = undefined;
1114// if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1115// const err = switch (windows.kernel32.GetLastError()) {
1116// else => |err| windows.unexpectedError(err),
1117// };
1118// await (async self.channel.put(err) catch unreachable);
1119// } else {
1120// // can't use @bytesToSlice because of the special variable length name field
1121// var ptr = event_buf[0..].ptr;
1122// const end_ptr = ptr + bytes_transferred;
1123// var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1124// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1125// ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1126// const emit = switch (ev.Action) {
1127// windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1128// windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1129// else => null,
1130// };
1131// if (emit) |id| {
1132// const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1133// const user_value = blk: {
1134// const held = await (async dir.table_lock.acquire() catch unreachable);
1135// defer held.release();
1136//
1137// if (dir.file_table.get(basename_utf16le)) |entry| {
1138// break :blk entry.value;
1139// } else {
1140// break :blk null;
1141// }
1142// };
1143// if (user_value) |v| {
1144// await (async self.channel.put(Event{
1145// .id = id,
1146// .data = v,
1147// }) catch unreachable);
1148// }
1149// }
1150// if (ev.NextEntryOffset == 0) break;
1151// }
1152// }
1153// }
1154// }
1155//
1156// pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1157// @panic("TODO");
1158// }
1159//
1160// async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1161// const loop = channel.loop;
1162//
1163// var watch = Self{
1164// .channel = channel,
1165// .os_data = OsData{
1166// .putter = @frame(),
1167// .inotify_fd = inotify_fd,
1168// .wd_table = OsData.WdTable.init(loop.allocator),
1169// .table_lock = event.Lock.init(loop),
1170// },
1171// };
1172// out_watch.* = &watch;
1173//
1174// loop.beginOneEvent();
1175//
1176// defer {
1177// watch.os_data.table_lock.deinit();
1178// var wd_it = watch.os_data.wd_table.iterator();
1179// while (wd_it.next()) |wd_entry| {
1180// var file_it = wd_entry.value.file_table.iterator();
1181// while (file_it.next()) |file_entry| {
1182// loop.allocator.free(file_entry.key);
1183// }
1184// loop.allocator.free(wd_entry.value.dirname);
1185// }
1186// loop.finishOneEvent();
1187// os.close(inotify_fd);
1188// channel.destroy();
1189// }
1190//
1191// var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1192//
1193// while (true) {
1194// const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1195// const errno = os.linux.getErrno(rc);
1196// switch (errno) {
1197// 0 => {
1198// // can't use @bytesToSlice because of the special variable length name field
1199// var ptr = event_buf[0..].ptr;
1200// const end_ptr = ptr + event_buf.len;
1201// var ev: *os.linux.inotify_event = undefined;
1202// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1203// ev = @ptrCast(*os.linux.inotify_event, ptr);
1204// if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1205// const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1206// const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1207// const user_value = blk: {
1208// const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1209// defer held.release();
1210//
1211// const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1212// if (dir.file_table.get(basename_with_null)) |entry| {
1213// break :blk entry.value;
1214// } else {
1215// break :blk null;
1216// }
1217// };
1218// if (user_value) |v| {
1219// await (async channel.put(Event{
1220// .id = WatchEventId.CloseWrite,
1221// .data = v,
1222// }) catch unreachable);
1223// }
1224// }
1225// }
1226// },
1227// os.linux.EINTR => continue,
1228// os.linux.EINVAL => unreachable,
1229// os.linux.EFAULT => unreachable,
1230// os.linux.EAGAIN => {
1231// (await (async loop.linuxWaitFd(
1232// inotify_fd,
1233// os.linux.EPOLLET | os.linux.EPOLLIN,
1234// ) catch unreachable)) catch |err| {
1235// const transformed_err = switch (err) {
1236// error.FileDescriptorAlreadyPresentInSet => unreachable,
1237// error.OperationCausesCircularLoop => unreachable,
1238// error.FileDescriptorNotRegistered => unreachable,
1239// error.FileDescriptorIncompatibleWithEpoll => unreachable,
1240// error.Unexpected => unreachable,
1241// else => |e| e,
1242// };
1243// await (async channel.put(transformed_err) catch unreachable);
1244// };
1245// },
1246// else => unreachable,
1247// }
1248// }
1249// }
1250// };
1251//}
13061252
13071253const test_tmp_dir = "std_event_fs_test";
13081254
1309// TODO this test is disabled until the coroutine rewrite is finished.
1255// TODO this test is disabled until the async function rewrite is finished.
13101256//test "write a file, watch it, write it again" {
13111257// return error.SkipZigTest;
13121258// const allocator = std.heap.direct_allocator;
......@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {
13551301
13561302 const ev = try async watch.channel.get();
13571303 var ev_consumed = false;
1358 defer if (!ev_consumed) cancel ev;
1304 defer if (!ev_consumed) await ev;
13591305
13601306 // overwrite line 2
13611307 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
......@@ -1397,11 +1343,11 @@ pub const OutStream = struct {
13971343 };
13981344 }
13991345
1400 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
1346 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
14011347 const self = @fieldParentPtr(OutStream, "stream", out_stream);
14021348 const offset = self.offset;
14031349 self.offset += bytes.len;
1404 return await (async pwritev(self.loop, self.fd, [][]const u8{bytes}, offset) catch unreachable);
1350 return pwritev(self.loop, self.fd, [][]const u8{bytes}, offset);
14051351 }
14061352};
14071353
......@@ -1423,9 +1369,9 @@ pub const InStream = struct {
14231369 };
14241370 }
14251371
1426 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
1372 fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
14271373 const self = @fieldParentPtr(InStream, "stream", in_stream);
1428 const amt = try await (async preadv(self.loop, self.fd, [][]u8{bytes}, self.offset) catch unreachable);
1374 const amt = try preadv(self.loop, self.fd, [][]u8{bytes}, self.offset);
14291375 self.offset += amt;
14301376 return amt;
14311377 }
std/event/future.zig+21-28
......@@ -2,13 +2,11 @@ const std = @import("../std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const builtin = @import("builtin");
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const Lock = std.event.Lock;
86const Loop = std.event.Loop;
97
108/// This is a value that starts out unavailable, until resolve() is called
11/// While it is unavailable, coroutines suspend when they try to get() it,
9/// While it is unavailable, functions suspend when they try to get() it,
1210/// and then are resumed when resolve() is called.
1311/// At this point the value remains forever available, and another resolve() is not allowed.
1412pub fn Future(comptime T: type) type {
......@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {
2321 available: u8,
2422
2523 const Self = @This();
26 const Queue = std.atomic.Queue(promise);
24 const Queue = std.atomic.Queue(anyframe);
2725
2826 pub fn init(loop: *Loop) Self {
2927 return Self{
......@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {
3735 /// available.
3836 /// Thread-safe.
3937 pub async fn get(self: *Self) *T {
40 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
38 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
4139 return &self.data;
4240 }
43 const held = await (async self.lock.acquire() catch unreachable);
41 const held = self.lock.acquire();
4442 held.release();
4543
4644 return &self.data;
......@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {
4947 /// Gets the data without waiting for it. If it's available, a pointer is
5048 /// returned. Otherwise, null is returned.
5149 pub fn getOrNull(self: *Self) ?*T {
52 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
50 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
5351 return &self.data;
5452 } else {
5553 return null;
......@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {
6260 /// It's not required to call start() before resolve() but it can be useful since
6361 /// this method is thread-safe.
6462 pub async fn start(self: *Self) ?*T {
65 const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
63 const state = @cmpxchgStrong(u8, &self.available, 0, 1, .SeqCst, .SeqCst) orelse return null;
6664 switch (state) {
6765 1 => {
68 const held = await (async self.lock.acquire() catch unreachable);
66 const held = self.lock.acquire();
6967 held.release();
7068 return &self.data;
7169 },
......@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {
7775 /// Make the data become available. May be called only once.
7876 /// Before calling this, modify the `data` property.
7977 pub fn resolve(self: *Self) void {
80 const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
78 const prev = @atomicRmw(u8, &self.available, .Xchg, 2, .SeqCst);
8179 assert(prev == 0 or prev == 1); // resolve() called twice
8280 Lock.Held.release(Lock.Held{ .lock = &self.lock });
8381 }
......@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {
8684
8785test "std.event.Future" {
8886 // https://github.com/ziglang/zig/issues/1908
89 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
87 if (builtin.single_threaded) return error.SkipZigTest;
9088
9189 const allocator = std.heap.direct_allocator;
9290
......@@ -94,38 +92,33 @@ test "std.event.Future" {
9492 try loop.initMultiThreaded(allocator);
9593 defer loop.deinit();
9694
97 const handle = try async<allocator> testFuture(&loop);
98 defer cancel handle;
95 const handle = async testFuture(&loop);
9996
10097 loop.run();
10198}
10299
103100async fn testFuture(loop: *Loop) void {
104 suspend {
105 resume @handle();
106 }
107101 var future = Future(i32).init(loop);
108102
109 const a = async waitOnFuture(&future) catch @panic("memory");
110 const b = async waitOnFuture(&future) catch @panic("memory");
111 const c = async resolveFuture(&future) catch @panic("memory");
103 const a = async waitOnFuture(&future);
104 const b = async waitOnFuture(&future);
105 const c = async resolveFuture(&future);
112106
113 const result = (await a) + (await b);
114 cancel c;
107 // TODO make this work:
108 //const result = (await a) + (await b);
109 const a_result = await a;
110 const b_result = await b;
111 const result = a_result + b_result;
112
113 await c;
115114 testing.expect(result == 12);
116115}
117116
118117async fn waitOnFuture(future: *Future(i32)) i32 {
119 suspend {
120 resume @handle();
121 }
122 return (await (async future.get() catch @panic("memory"))).*;
118 return future.get().*;
123119}
124120
125121async fn resolveFuture(future: *Future(i32)) void {
126 suspend {
127 resume @handle();
128 }
129122 future.data = 6;
130123 future.resolve();
131124}
std/event/group.zig+29-67
......@@ -2,46 +2,33 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Lock = std.event.Lock;
44const Loop = std.event.Loop;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const testing = std.testing;
86
97/// ReturnType must be `void` or `E!void`
108pub fn Group(comptime ReturnType: type) type {
119 return struct {
12 coro_stack: Stack,
10 frame_stack: Stack,
1311 alloc_stack: Stack,
1412 lock: Lock,
1513
1614 const Self = @This();
1715
1816 const Error = switch (@typeInfo(ReturnType)) {
19 builtin.TypeId.ErrorUnion => |payload| payload.error_set,
17 .ErrorUnion => |payload| payload.error_set,
2018 else => void,
2119 };
22 const Stack = std.atomic.Stack(promise->ReturnType);
20 const Stack = std.atomic.Stack(anyframe->ReturnType);
2321
2422 pub fn init(loop: *Loop) Self {
2523 return Self{
26 .coro_stack = Stack.init(),
24 .frame_stack = Stack.init(),
2725 .alloc_stack = Stack.init(),
2826 .lock = Lock.init(loop),
2927 };
3028 }
3129
32 /// Cancel all the outstanding promises. Can be called even if wait was already called.
33 pub fn deinit(self: *Self) void {
34 while (self.coro_stack.pop()) |node| {
35 cancel node.data;
36 }
37 while (self.alloc_stack.pop()) |node| {
38 cancel node.data;
39 self.lock.loop.allocator.destroy(node);
40 }
41 }
42
43 /// Add a promise to the group. Thread-safe.
44 pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
30 /// Add a frame to the group. Thread-safe.
31 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) {
4532 const node = try self.lock.loop.allocator.create(Stack.Node);
4633 node.* = Stack.Node{
4734 .next = undefined,
......@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {
5138 }
5239
5340 /// Add a node to the group. Thread-safe. Cannot fail.
54 /// `node.data` should be the promise handle to add to the group.
55 /// The node's memory should be in the coroutine frame of
41 /// `node.data` should be the frame handle to add to the group.
42 /// The node's memory should be in the function frame of
5643 /// the handle that is in the node, or somewhere guaranteed to live
5744 /// at least as long.
5845 pub fn addNode(self: *Self, node: *Stack.Node) void {
59 self.coro_stack.push(node);
60 }
61
62 /// This is equivalent to an async call, but the async function is added to the group, instead
63 /// of returning a promise. func must be async and have return type ReturnType.
64 /// Thread-safe.
65 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {
66 const S = struct {
67 async fn asyncFunc(node: **Stack.Node, args2: ...) ReturnType {
68 // TODO this is a hack to make the memory following be inside the coro frame
69 suspend {
70 var my_node: Stack.Node = undefined;
71 node.* = &my_node;
72 resume @handle();
73 }
74
75 // TODO this allocation elision should be guaranteed because we await it in
76 // this coro frame
77 return await (async func(args2) catch unreachable);
78 }
79 };
80 var node: *Stack.Node = undefined;
81 const handle = try async<self.lock.loop.allocator> S.asyncFunc(&node, args);
82 node.* = Stack.Node{
83 .next = undefined,
84 .data = handle,
85 };
86 self.coro_stack.push(node);
46 self.frame_stack.push(node);
8747 }
8848
8949 /// Wait for all the calls and promises of the group to complete.
9050 /// Thread-safe.
9151 /// Safe to call any number of times.
9252 pub async fn wait(self: *Self) ReturnType {
93 // TODO catch unreachable because the allocation can be grouped with
94 // the coro frame allocation
95 const held = await (async self.lock.acquire() catch unreachable);
53 const held = self.lock.acquire();
9654 defer held.release();
9755
98 while (self.coro_stack.pop()) |node| {
56 var result: ReturnType = {};
57
58 while (self.frame_stack.pop()) |node| {
9959 if (Error == void) {
10060 await node.data;
10161 } else {
10262 (await node.data) catch |err| {
103 self.deinit();
104 return err;
63 result = err;
10564 };
10665 }
10766 }
......@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {
11271 await handle;
11372 } else {
11473 (await handle) catch |err| {
115 self.deinit();
116 return err;
74 result = err;
11775 };
11876 }
11977 }
78 return result;
12079 }
12180 };
12281}
......@@ -131,8 +90,7 @@ test "std.event.Group" {
13190 try loop.initMultiThreaded(allocator);
13291 defer loop.deinit();
13392
134 const handle = try async<allocator> testGroup(&loop);
135 defer cancel handle;
93 const handle = async testGroup(&loop);
13694
13795 loop.run();
13896}
......@@ -140,26 +98,30 @@ test "std.event.Group" {
14098async fn testGroup(loop: *Loop) void {
14199 var count: usize = 0;
142100 var group = Group(void).init(loop);
143 group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");
144 group.call(increaseByTen, &count) catch @panic("memory");
145 await (async group.wait() catch @panic("memory"));
101 var sleep_a_little_frame = async sleepALittle(&count);
102 group.add(&sleep_a_little_frame) catch @panic("memory");
103 var increase_by_ten_frame = async increaseByTen(&count);
104 group.add(&increase_by_ten_frame) catch @panic("memory");
105 group.wait();
146106 testing.expect(count == 11);
147107
148108 var another = Group(anyerror!void).init(loop);
149 another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");
150 another.call(doSomethingThatFails) catch @panic("memory");
151 testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory")));
109 var something_else_frame = async somethingElse();
110 another.add(&something_else_frame) catch @panic("memory");
111 var something_that_fails_frame = async doSomethingThatFails();
112 another.add(&something_that_fails_frame) catch @panic("memory");
113 testing.expectError(error.ItBroke, another.wait());
152114}
153115
154116async fn sleepALittle(count: *usize) void {
155117 std.time.sleep(1 * std.time.millisecond);
156 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
118 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
157119}
158120
159121async fn increaseByTen(count: *usize) void {
160122 var i: usize = 0;
161123 while (i < 10) : (i += 1) {
162 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
124 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
163125 }
164126}
165127
std/event/io.zig+9-10
......@@ -1,6 +1,5 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;
43const assert = std.debug.assert;
54const mem = std.mem;
65
......@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {
1211 /// Return the number of bytes read. It may be less than buffer.len.
1312 /// If the number of bytes read is 0, it means end of stream.
1413 /// End of stream is not an error condition.
15 readFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!usize,
14 readFn: async fn (self: *Self, buffer: []u8) Error!usize,
1615
1716 /// Return the number of bytes read. It may be less than buffer.len.
1817 /// If the number of bytes read is 0, it means end of stream.
1918 /// End of stream is not an error condition.
2019 pub async fn read(self: *Self, buffer: []u8) !usize {
21 return await (async self.readFn(self, buffer) catch unreachable);
20 return self.readFn(self, buffer);
2221 }
2322
2423 /// Return the number of bytes read. If it is less than buffer.len
......@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {
2625 pub async fn readFull(self: *Self, buffer: []u8) !usize {
2726 var index: usize = 0;
2827 while (index != buf.len) {
29 const amt_read = try await (async self.read(buf[index..]) catch unreachable);
28 const amt_read = try self.read(buf[index..]);
3029 if (amt_read == 0) return index;
3130 index += amt_read;
3231 }
......@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {
3534
3635 /// Same as `readFull` but end of stream returns `error.EndOfStream`.
3736 pub async fn readNoEof(self: *Self, buf: []u8) !void {
38 const amt_read = try await (async self.readFull(buf[index..]) catch unreachable);
37 const amt_read = try self.readFull(buf[index..]);
3938 if (amt_read < buf.len) return error.EndOfStream;
4039 }
4140
4241 pub async fn readIntLittle(self: *Self, comptime T: type) !T {
4342 var bytes: [@sizeOf(T)]u8 = undefined;
44 try await (async self.readNoEof(bytes[0..]) catch unreachable);
43 try self.readNoEof(bytes[0..]);
4544 return mem.readIntLittle(T, &bytes);
4645 }
4746
4847 pub async fn readIntBe(self: *Self, comptime T: type) !T {
4948 var bytes: [@sizeOf(T)]u8 = undefined;
50 try await (async self.readNoEof(bytes[0..]) catch unreachable);
49 try self.readNoEof(bytes[0..]);
5150 return mem.readIntBig(T, &bytes);
5251 }
5352
5453 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
5554 var bytes: [@sizeOf(T)]u8 = undefined;
56 try await (async self.readNoEof(bytes[0..]) catch unreachable);
55 try self.readNoEof(bytes[0..]);
5756 return mem.readInt(T, &bytes, endian);
5857 }
5958
......@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {
6160 // Only extern and packed structs have defined in-memory layout.
6261 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
6362 var res: [1]T = undefined;
64 try await (async self.readNoEof(@sliceToBytes(res[0..])) catch unreachable);
63 try self.readNoEof(@sliceToBytes(res[0..]));
6564 return res[0];
6665 }
6766 };
......@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {
7271 const Self = @This();
7372 pub const Error = WriteError;
7473
75 writeFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!void,
74 writeFn: async fn (self: *Self, buffer: []u8) Error!void,
7675 };
7776}
std/event/lock.zig+23-36
......@@ -3,12 +3,10 @@ const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
55const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
86const Loop = std.event.Loop;
97
108/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and
9/// Functions which are waiting for the lock are suspended, and
1210/// are resumed when the lock is released, in order.
1311/// Allows only one actor to hold the lock.
1412pub const Lock = struct {
......@@ -17,7 +15,7 @@ pub const Lock = struct {
1715 queue: Queue,
1816 queue_empty_bit: u8, // TODO make this a bool
1917
20 const Queue = std.atomic.Queue(promise);
18 const Queue = std.atomic.Queue(anyframe);
2119
2220 pub const Held = struct {
2321 lock: *Lock,
......@@ -30,19 +28,19 @@ pub const Lock = struct {
3028 }
3129
3230 // We need to release the lock.
33 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
34 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
31 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
32 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
3533
3634 // There might be a queue item. If we know the queue is empty, we can be done,
3735 // because the other actor will try to obtain the lock.
3836 // But if there's a queue item, we are the actor which must loop and attempt
3937 // to grab the lock again.
40 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
38 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
4139 return;
4240 }
4341
4442 while (true) {
45 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
43 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 1, .SeqCst);
4644 if (old_bit != 0) {
4745 // We did not obtain the lock. Great, the queue is someone else's problem.
4846 return;
......@@ -55,11 +53,11 @@ pub const Lock = struct {
5553 }
5654
5755 // Release the lock again.
58 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
59 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
56 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
57 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
6058
6159 // Find out if we can be done.
62 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
60 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
6361 return;
6462 }
6563 }
......@@ -88,28 +86,23 @@ pub const Lock = struct {
8886 /// All calls to acquire() and release() must complete before calling deinit().
8987 pub fn deinit(self: *Lock) void {
9088 assert(self.shared_bit == 0);
91 while (self.queue.get()) |node| cancel node.data;
89 while (self.queue.get()) |node| resume node.data;
9290 }
9391
9492 pub async fn acquire(self: *Lock) Held {
95 // TODO explicitly put this memory in the coroutine frame #1194
96 suspend {
97 resume @handle();
98 }
99 var my_tick_node = Loop.NextTickNode.init(@handle());
93 var my_tick_node = Loop.NextTickNode.init(@frame());
10094
10195 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
10296 suspend {
10397 self.queue.put(&my_tick_node);
10498
105 // At this point, we are in the queue, so we might have already been resumed and this coroutine
106 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
99 // At this point, we are in the queue, so we might have already been resumed.
107100
108101 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
109102 // will attempt to grab the lock.
110 _ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
103 _ = @atomicRmw(u8, &self.queue_empty_bit, .Xchg, 0, .SeqCst);
111104
112 const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
105 const old_bit = @atomicRmw(u8, &self.shared_bit, .Xchg, 1, .SeqCst);
113106 if (old_bit == 0) {
114107 if (self.queue.get()) |node| {
115108 // Whether this node is us or someone else, we tail resume it.
......@@ -123,8 +116,7 @@ pub const Lock = struct {
123116};
124117
125118test "std.event.Lock" {
126 // TODO https://github.com/ziglang/zig/issues/2377
127 if (true) return error.SkipZigTest;
119 // TODO https://github.com/ziglang/zig/issues/1908
128120 if (builtin.single_threaded) return error.SkipZigTest;
129121
130122 const allocator = std.heap.direct_allocator;
......@@ -136,39 +128,34 @@ test "std.event.Lock" {
136128 var lock = Lock.init(&loop);
137129 defer lock.deinit();
138130
139 const handle = try async<allocator> testLock(&loop, &lock);
140 defer cancel handle;
131 _ = async testLock(&loop, &lock);
141132 loop.run();
142133
143134 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
144135}
145136
146137async fn testLock(loop: *Loop, lock: *Lock) void {
147 // TODO explicitly put next tick node memory in the coroutine frame #1194
148 suspend {
149 resume @handle();
150 }
151 const handle1 = async lockRunner(lock) catch @panic("out of memory");
138 const handle1 = async lockRunner(lock);
152139 var tick_node1 = Loop.NextTickNode{
153140 .prev = undefined,
154141 .next = undefined,
155 .data = handle1,
142 .data = &handle1,
156143 };
157144 loop.onNextTick(&tick_node1);
158145
159 const handle2 = async lockRunner(lock) catch @panic("out of memory");
146 const handle2 = async lockRunner(lock);
160147 var tick_node2 = Loop.NextTickNode{
161148 .prev = undefined,
162149 .next = undefined,
163 .data = handle2,
150 .data = &handle2,
164151 };
165152 loop.onNextTick(&tick_node2);
166153
167 const handle3 = async lockRunner(lock) catch @panic("out of memory");
154 const handle3 = async lockRunner(lock);
168155 var tick_node3 = Loop.NextTickNode{
169156 .prev = undefined,
170157 .next = undefined,
171 .data = handle3,
158 .data = &handle3,
172159 };
173160 loop.onNextTick(&tick_node3);
174161
......@@ -185,7 +172,7 @@ async fn lockRunner(lock: *Lock) void {
185172
186173 var i: usize = 0;
187174 while (i < shared_test_data.len) : (i += 1) {
188 const lock_promise = async lock.acquire() catch @panic("out of memory");
175 const lock_promise = async lock.acquire();
189176 const handle = await lock_promise;
190177 defer handle.release();
191178
std/event/locked.zig+1-1
......@@ -3,7 +3,7 @@ const Lock = std.event.Lock;
33const Loop = std.event.Loop;
44
55/// Thread-safe async/await lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and
6/// Functions which are waiting for the lock are suspended, and
77/// are resumed when the lock is released, in order.
88pub fn Locked(comptime T: type) type {
99 return struct {
std/event/loop.zig+83-69
......@@ -1,5 +1,6 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const root = @import("root");
34const assert = std.debug.assert;
45const testing = std.testing;
56const mem = std.mem;
......@@ -13,7 +14,7 @@ const Thread = std.Thread;
1314
1415pub const Loop = struct {
1516 allocator: *mem.Allocator,
16 next_tick_queue: std.atomic.Queue(promise),
17 next_tick_queue: std.atomic.Queue(anyframe),
1718 os_data: OsData,
1819 final_resume_node: ResumeNode,
1920 pending_event_count: usize,
......@@ -24,11 +25,11 @@ pub const Loop = struct {
2425 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
2526 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,
2627
27 pub const NextTickNode = std.atomic.Queue(promise).Node;
28 pub const NextTickNode = std.atomic.Queue(anyframe).Node;
2829
2930 pub const ResumeNode = struct {
3031 id: Id,
31 handle: promise,
32 handle: anyframe,
3233 overlapped: Overlapped,
3334
3435 pub const overlapped_init = switch (builtin.os) {
......@@ -85,18 +86,43 @@ pub const Loop = struct {
8586 };
8687 };
8788
89 pub const IoMode = enum {
90 blocking,
91 evented,
92 };
93 pub const io_mode: IoMode = if (@hasDecl(root, "io_mode")) root.io_mode else IoMode.blocking;
94 var global_instance_state: Loop = undefined;
95 const default_instance: ?*Loop = switch (io_mode) {
96 .blocking => null,
97 .evented => &global_instance_state,
98 };
99 pub const instance: ?*Loop = if (@hasDecl(root, "event_loop")) root.event_loop else default_instance;
100
101 /// TODO copy elision / named return values so that the threads referencing *Loop
102 /// have the correct pointer value.
103 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
104 pub fn init(self: *Loop, allocator: *mem.Allocator) !void {
105 if (builtin.single_threaded) {
106 return self.initSingleThreaded(allocator);
107 } else {
108 return self.initMultiThreaded(allocator);
109 }
110 }
111
88112 /// After initialization, call run().
89113 /// TODO copy elision / named return values so that the threads referencing *Loop
90114 /// have the correct pointer value.
115 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
91116 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {
92117 return self.initInternal(allocator, 1);
93118 }
94119
95120 /// The allocator must be thread-safe because we use it for multiplexing
96 /// coroutines onto kernel threads.
121 /// async functions onto kernel threads.
97122 /// After initialization, call run().
98123 /// TODO copy elision / named return values so that the threads referencing *Loop
99124 /// have the correct pointer value.
125 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
100126 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
101127 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
102128 const core_count = try Thread.cpuCount();
......@@ -110,7 +136,7 @@ pub const Loop = struct {
110136 .pending_event_count = 1,
111137 .allocator = allocator,
112138 .os_data = undefined,
113 .next_tick_queue = std.atomic.Queue(promise).init(),
139 .next_tick_queue = std.atomic.Queue(anyframe).init(),
114140 .extra_threads = undefined,
115141 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
116142 .eventfd_resume_nodes = undefined,
......@@ -397,7 +423,7 @@ pub const Loop = struct {
397423 }
398424 }
399425
400 /// resume_node must live longer than the promise that it holds a reference to.
426 /// resume_node must live longer than the anyframe that it holds a reference to.
401427 /// flags must contain EPOLLET
402428 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403429 assert(flags & os.EPOLLET == os.EPOLLET);
......@@ -428,11 +454,10 @@ pub const Loop = struct {
428454 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {
429455 defer self.linuxRemoveFd(fd);
430456 suspend {
431 // TODO explicitly put this memory in the coroutine frame #1194
432457 var resume_node = ResumeNode.Basic{
433458 .base = ResumeNode{
434459 .id = ResumeNode.Id.Basic,
435 .handle = @handle(),
460 .handle = @frame(),
436461 .overlapped = ResumeNode.overlapped_init,
437462 },
438463 };
......@@ -441,14 +466,10 @@ pub const Loop = struct {
441466 }
442467
443468 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
444 // TODO #1194
445 suspend {
446 resume @handle();
447 }
448469 var resume_node = ResumeNode.Basic{
449470 .base = ResumeNode{
450471 .id = ResumeNode.Id.Basic,
451 .handle = @handle(),
472 .handle = @frame(),
452473 .overlapped = ResumeNode.overlapped_init,
453474 },
454475 .kev = undefined,
......@@ -460,7 +481,7 @@ pub const Loop = struct {
460481 return resume_node.kev;
461482 }
462483
463 /// resume_node must live longer than the promise that it holds a reference to.
484 /// resume_node must live longer than the anyframe that it holds a reference to.
464485 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465486 self.beginOneEvent();
466487 errdefer self.finishOneEvent();
......@@ -561,10 +582,10 @@ pub const Loop = struct {
561582 self.workerRun();
562583
563584 switch (builtin.os) {
564 builtin.Os.linux,
565 builtin.Os.macosx,
566 builtin.Os.freebsd,
567 builtin.Os.netbsd,
585 .linux,
586 .macosx,
587 .freebsd,
588 .netbsd,
568589 => self.os_data.fs_thread.wait(),
569590 else => {},
570591 }
......@@ -574,45 +595,39 @@ pub const Loop = struct {
574595 }
575596 }
576597
577 /// This is equivalent to an async call, except instead of beginning execution of the async function,
578 /// it immediately returns to the caller, and the async function is queued in the event loop. It still
579 /// returns a promise to be awaited.
580 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {
581 const S = struct {
582 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
583 suspend {
584 handle.* = @handle();
585 var my_tick_node = Loop.NextTickNode{
586 .prev = undefined,
587 .next = undefined,
588 .data = @handle(),
589 };
590 loop.onNextTick(&my_tick_node);
591 }
592 // TODO guaranteed allocation elision for await in same func as async
593 return await (async func(args2) catch unreachable);
594 }
595 };
596 var handle: promise->@typeOf(func).ReturnType = undefined;
597 return async<self.allocator> S.asyncFunc(self, &handle, args);
598 /// This is equivalent to function call, except it calls `startCpuBoundOperation` first.
599 pub fn call(comptime func: var, args: ...) @typeOf(func).ReturnType {
600 startCpuBoundOperation();
601 return func(args);
598602 }
599603
600 /// Awaiting a yield lets the event loop run, starting any unstarted async operations.
604 /// Yielding lets the event loop run, starting any unstarted async operations.
601605 /// Note that async operations automatically start when a function yields for any other reason,
602606 /// for example, when async I/O is performed. This function is intended to be used only when
603607 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
604608 /// is performed.
605 pub async fn yield(self: *Loop) void {
609 pub fn yield(self: *Loop) void {
606610 suspend {
607 var my_tick_node = Loop.NextTickNode{
611 var my_tick_node = NextTickNode{
608612 .prev = undefined,
609613 .next = undefined,
610 .data = @handle(),
614 .data = @frame(),
611615 };
612616 self.onNextTick(&my_tick_node);
613617 }
614618 }
615619
620 /// If the build is multi-threaded and there is an event loop, then it calls `yield`. Otherwise,
621 /// does nothing.
622 pub fn startCpuBoundOperation() void {
623 if (builtin.single_threaded) {
624 return;
625 } else if (instance) |event_loop| {
626 event_loop.yield();
627 }
628 }
629
630
616631 /// call finishOneEvent when done
617632 pub fn beginOneEvent(self: *Loop) void {
618633 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
......@@ -672,9 +687,9 @@ pub const Loop = struct {
672687 const handle = resume_node.handle;
673688 const resume_node_id = resume_node.id;
674689 switch (resume_node_id) {
675 ResumeNode.Id.Basic => {},
676 ResumeNode.Id.Stop => return,
677 ResumeNode.Id.EventFd => {
690 .Basic => {},
691 .Stop => return,
692 .EventFd => {
678693 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679694 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680695 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
......@@ -696,12 +711,12 @@ pub const Loop = struct {
696711 const handle = resume_node.handle;
697712 const resume_node_id = resume_node.id;
698713 switch (resume_node_id) {
699 ResumeNode.Id.Basic => {
714 .Basic => {
700715 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);
701716 basic_node.kev = ev;
702717 },
703 ResumeNode.Id.Stop => return,
704 ResumeNode.Id.EventFd => {
718 .Stop => return,
719 .EventFd => {
705720 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
706721 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
707722 self.available_eventfd_resume_nodes.push(stack_node);
......@@ -730,9 +745,9 @@ pub const Loop = struct {
730745 const handle = resume_node.handle;
731746 const resume_node_id = resume_node.id;
732747 switch (resume_node_id) {
733 ResumeNode.Id.Basic => {},
734 ResumeNode.Id.Stop => return,
735 ResumeNode.Id.EventFd => {
748 .Basic => {},
749 .Stop => return,
750 .EventFd => {
736751 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
737752 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
738753 self.available_eventfd_resume_nodes.push(stack_node);
......@@ -750,12 +765,12 @@ pub const Loop = struct {
750765 self.beginOneEvent(); // finished in posixFsRun after processing the msg
751766 self.os_data.fs_queue.put(request_node);
752767 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
768 .macosx, .freebsd, .netbsd => {
754769 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755770 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756771 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757772 },
758 builtin.Os.linux => {
773 .linux => {
759774 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760775 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761776 switch (os.linux.getErrno(rc)) {
......@@ -781,18 +796,18 @@ pub const Loop = struct {
781796 }
782797 while (self.os_data.fs_queue.get()) |node| {
783798 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {
799 .End => return,
800 .PWriteV => |*msg| {
786801 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787802 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {
803 .PReadV => |*msg| {
789804 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790805 },
791 @TagType(fs.Request.Msg).Open => |*msg| {
806 .Open => |*msg| {
792807 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793808 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {
809 .Close => |*msg| os.close(msg.fd),
810 .WriteFile => |*msg| blk: {
796811 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797812 os.O_CLOEXEC | os.O_TRUNC;
798813 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
......@@ -804,11 +819,11 @@ pub const Loop = struct {
804819 },
805820 }
806821 switch (node.data.finish) {
807 @TagType(fs.Request.Finish).TickNode => |*tick_node| self.onNextTick(tick_node),
808 @TagType(fs.Request.Finish).DeallocCloseOperation => |close_op| {
822 .TickNode => |*tick_node| self.onNextTick(tick_node),
823 .DeallocCloseOperation => |close_op| {
809824 self.allocator.destroy(close_op);
810825 },
811 @TagType(fs.Request.Finish).NoAction => {},
826 .NoAction => {},
812827 }
813828 self.finishOneEvent();
814829 }
......@@ -864,7 +879,7 @@ pub const Loop = struct {
864879
865880test "std.event.Loop - basic" {
866881 // https://github.com/ziglang/zig/issues/1908
867 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
882 if (builtin.single_threaded) return error.SkipZigTest;
868883
869884 const allocator = std.heap.direct_allocator;
870885
......@@ -877,7 +892,7 @@ test "std.event.Loop - basic" {
877892
878893test "std.event.Loop - call" {
879894 // https://github.com/ziglang/zig/issues/1908
880 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
895 if (builtin.single_threaded) return error.SkipZigTest;
881896
882897 const allocator = std.heap.direct_allocator;
883898
......@@ -886,9 +901,8 @@ test "std.event.Loop - call" {
886901 defer loop.deinit();
887902
888903 var did_it = false;
889 const handle = try loop.call(testEventLoop);
890 const handle2 = try loop.call(testEventLoop2, handle, &did_it);
891 defer cancel handle2;
904 const handle = async Loop.call(testEventLoop);
905 const handle2 = async Loop.call(testEventLoop2, &handle, &did_it);
892906
893907 loop.run();
894908
......@@ -899,7 +913,7 @@ async fn testEventLoop() i32 {
899913 return 1234;
900914}
901915
902async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
916async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
903917 const value = await h;
904918 testing.expect(value == 1234);
905919 did_it.* = true;
std/event/net.zig+27-38
......@@ -9,24 +9,24 @@ const File = std.fs.File;
99const fd_t = os.fd_t;
1010
1111pub const Server = struct {
12 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
12 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
1313
1414 loop: *Loop,
1515 sockfd: ?i32,
16 accept_coro: ?promise,
16 accept_frame: ?anyframe,
1717 listen_address: std.net.Address,
1818
1919 waiting_for_emfile_node: PromiseNode,
2020 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.TailQueue(promise).Node;
22 const PromiseNode = std.TailQueue(anyframe).Node;
2323
2424 pub fn init(loop: *Loop) Server {
25 // TODO can't initialize handler coroutine here because we need well defined copy elision
25 // TODO can't initialize handler here because we need well defined copy elision
2626 return Server{
2727 .loop = loop,
2828 .sockfd = null,
29 .accept_coro = null,
29 .accept_frame = null,
3030 .handleRequestFn = undefined,
3131 .waiting_for_emfile_node = undefined,
3232 .listen_address = undefined,
......@@ -41,7 +41,7 @@ pub const Server = struct {
4141 pub fn listen(
4242 self: *Server,
4343 address: *const std.net.Address,
44 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
44 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
4545 ) !void {
4646 self.handleRequestFn = handleRequestFn;
4747
......@@ -53,10 +53,10 @@ pub const Server = struct {
5353 try os.listen(sockfd, os.SOMAXCONN);
5454 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
5555
56 self.accept_coro = try async<self.loop.allocator> Server.handler(self);
57 errdefer cancel self.accept_coro.?;
56 self.accept_frame = async Server.handler(self);
57 errdefer await self.accept_frame.?;
5858
59 self.listen_resume_node.handle = self.accept_coro.?;
59 self.listen_resume_node.handle = self.accept_frame.?;
6060 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
6161 errdefer self.loop.removeFd(sockfd);
6262 }
......@@ -71,7 +71,7 @@ pub const Server = struct {
7171 }
7272
7373 pub fn deinit(self: *Server) void {
74 if (self.accept_coro) |accept_coro| cancel accept_coro;
74 if (self.accept_frame) |accept_frame| await accept_frame;
7575 if (self.sockfd) |sockfd| os.close(sockfd);
7676 }
7777
......@@ -86,12 +86,7 @@ pub const Server = struct {
8686 continue;
8787 }
8888 var socket = File.openHandle(accepted_fd);
89 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {
90 error.OutOfMemory => {
91 socket.close();
92 continue;
93 },
94 };
89 self.handleRequestFn(self, &accepted_addr, socket);
9590 } else |err| switch (err) {
9691 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
9792 error.ConnectionAborted => continue,
......@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
124119 mem.copy(u8, sock_addr.path[0..], path);
125120 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
126121 try os.connect_async(sockfd, &sock_addr, size);
127 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
122 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
128123 try os.getsockoptError(sockfd);
129124
130125 return sockfd;
......@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize
149144 .iov_len = buffer.len,
150145 };
151146 const iovs: *const [1]os.iovec = &iov;
152 return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);
147 return readvPosix(loop, fd, iovs, 1);
153148}
154149
155150pub const WriteError = error{};
......@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr
160155 .iov_len = buffer.len,
161156 };
162157 const iovs: *const [1]os.iovec_const = &iov;
163 return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);
158 return writevPosix(loop, fd, iovs, 1);
164159}
165160
166161pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
......@@ -174,7 +169,7 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, cou
174169 os.EINVAL => unreachable,
175170 os.EFAULT => unreachable,
176171 os.EAGAIN => {
177 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);
172 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT);
178173 continue;
179174 },
180175 os.EBADF => unreachable, // always a race condition
......@@ -205,7 +200,7 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count:
205200 os.EINVAL => unreachable,
206201 os.EFAULT => unreachable,
207202 os.EAGAIN => {
208 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);
203 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
209204 continue;
210205 },
211206 os.EBADF => unreachable, // always a race condition
......@@ -232,7 +227,7 @@ pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
232227 };
233228 }
234229
235 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
230 return writevPosix(loop, fd, iovecs.ptr, data.len);
236231}
237232
238233pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
......@@ -246,7 +241,7 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
246241 };
247242 }
248243
249 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
244 return readvPosix(loop, fd, iovecs.ptr, data.len);
250245}
251246
252247pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
......@@ -256,7 +251,7 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
256251 errdefer os.close(sockfd);
257252
258253 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
259 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
254 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
260255 try os.getsockoptError(sockfd);
261256
262257 return File.openHandle(sockfd);
......@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {
275270 tcp_server: Server,
276271
277272 const Self = @This();
278 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
273 async fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
279274 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
280275 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
281276 defer socket.close();
282 // TODO guarantee elision of this allocation
283 const next_handler = async errorableHandler(self, _addr, socket) catch unreachable;
284 (await next_handler) catch |err| {
277 const next_handler = errorableHandler(self, _addr, socket) catch |err| {
285278 std.debug.panic("unable to handle connection: {}\n", err);
286279 };
287 suspend {
288 cancel @handle();
289 }
290280 }
291281 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
292282 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
......@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {
306296 defer server.tcp_server.deinit();
307297 try server.tcp_server.listen(&addr, MyServer.handler);
308298
309 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
310 defer cancel p;
299 _ = async doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
311300 loop.run();
312301}
313302
314303async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
315304 errdefer @panic("test failure");
316305
317 var socket_file = try await try async connect(loop, address);
306 var socket_file = try connect(loop, address);
318307 defer socket_file.close();
319308
320309 var buf: [512]u8 = undefined;
......@@ -340,9 +329,9 @@ pub const OutStream = struct {
340329 };
341330 }
342331
343 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
332 async fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
344333 const self = @fieldParentPtr(OutStream, "stream", out_stream);
345 return await (async write(self.loop, self.fd, bytes) catch unreachable);
334 return write(self.loop, self.fd, bytes);
346335 }
347336};
348337
......@@ -362,8 +351,8 @@ pub const InStream = struct {
362351 };
363352 }
364353
365 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
354 async fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
366355 const self = @fieldParentPtr(InStream, "stream", in_stream);
367 return await (async read(self.loop, self.fd, bytes) catch unreachable);
356 return read(self.loop, self.fd, bytes);
368357 }
369358};
std/event/rwlock.zig+46-47
......@@ -3,12 +3,10 @@ const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
55const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
86const Loop = std.event.Loop;
97
108/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and
9/// Functions which are waiting for the lock are suspended, and
1210/// are resumed when the lock is released, in order.
1311/// Many readers can hold the lock at the same time; however locking for writing is exclusive.
1412/// When a read lock is held, it will not be released until the reader queue is empty.
......@@ -28,19 +26,19 @@ pub const RwLock = struct {
2826 const ReadLock = 2;
2927 };
3028
31 const Queue = std.atomic.Queue(promise);
29 const Queue = std.atomic.Queue(anyframe);
3230
3331 pub const HeldRead = struct {
3432 lock: *RwLock,
3533
3634 pub fn release(self: HeldRead) void {
3735 // If other readers still hold the lock, we're done.
38 if (@atomicRmw(usize, &self.lock.reader_lock_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst) != 1) {
36 if (@atomicRmw(usize, &self.lock.reader_lock_count, .Sub, 1, .SeqCst) != 1) {
3937 return;
4038 }
4139
42 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
43 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
40 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
41 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
4442 // Didn't unlock. Someone else's problem.
4543 return;
4644 }
......@@ -61,17 +59,17 @@ pub const RwLock = struct {
6159 }
6260
6361 // We need to release the write lock. Check if any readers are waiting to grab the lock.
64 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
62 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, .SeqCst) == 0) {
6563 // Switch to a read lock.
66 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.ReadLock, AtomicOrder.SeqCst);
64 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.ReadLock, .SeqCst);
6765 while (self.lock.reader_queue.get()) |node| {
6866 self.lock.loop.onNextTick(node);
6967 }
7068 return;
7169 }
7270
73 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
74 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);
71 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
72 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.Unlocked, .SeqCst);
7573
7674 self.lock.commonPostUnlock();
7775 }
......@@ -93,32 +91,30 @@ pub const RwLock = struct {
9391 /// All calls to acquire() and release() must complete before calling deinit().
9492 pub fn deinit(self: *RwLock) void {
9593 assert(self.shared_state == State.Unlocked);
96 while (self.writer_queue.get()) |node| cancel node.data;
97 while (self.reader_queue.get()) |node| cancel node.data;
94 while (self.writer_queue.get()) |node| resume node.data;
95 while (self.reader_queue.get()) |node| resume node.data;
9896 }
9997
10098 pub async fn acquireRead(self: *RwLock) HeldRead {
101 _ = @atomicRmw(usize, &self.reader_lock_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
99 _ = @atomicRmw(usize, &self.reader_lock_count, .Add, 1, .SeqCst);
102100
103101 suspend {
104 // TODO explicitly put this memory in the coroutine frame #1194
105102 var my_tick_node = Loop.NextTickNode{
106 .data = @handle(),
103 .data = @frame(),
107104 .prev = undefined,
108105 .next = undefined,
109106 };
110107
111108 self.reader_queue.put(&my_tick_node);
112109
113 // At this point, we are in the reader_queue, so we might have already been resumed and this coroutine
114 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
110 // At this point, we are in the reader_queue, so we might have already been resumed.
115111
116112 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
117113 // some actor will attempt to grab the lock.
118 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
114 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 0, .SeqCst);
119115
120116 // Here we don't care if we are the one to do the locking or if it was already locked for reading.
121 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |old_state| old_state == State.ReadLock else true;
117 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst)) |old_state| old_state == State.ReadLock else true;
122118 if (have_read_lock) {
123119 // Give out all the read locks.
124120 if (self.reader_queue.get()) |first_node| {
......@@ -134,24 +130,22 @@ pub const RwLock = struct {
134130
135131 pub async fn acquireWrite(self: *RwLock) HeldWrite {
136132 suspend {
137 // TODO explicitly put this memory in the coroutine frame #1194
138133 var my_tick_node = Loop.NextTickNode{
139 .data = @handle(),
134 .data = @frame(),
140135 .prev = undefined,
141136 .next = undefined,
142137 };
143138
144139 self.writer_queue.put(&my_tick_node);
145140
146 // At this point, we are in the writer_queue, so we might have already been resumed and this coroutine
147 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
141 // At this point, we are in the writer_queue, so we might have already been resumed.
148142
149143 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
150144 // some actor will attempt to grab the lock.
151 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
145 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 0, .SeqCst);
152146
153147 // Here we must be the one to acquire the write lock. It cannot already be locked.
154 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null) {
148 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) == null) {
155149 // We now have a write lock.
156150 if (self.writer_queue.get()) |node| {
157151 // Whether this node is us or someone else, we tail resume it.
......@@ -169,8 +163,8 @@ pub const RwLock = struct {
169163 // obtain the lock.
170164 // But if there's a writer_queue item or a reader_queue item,
171165 // we are the actor which must loop and attempt to grab the lock again.
172 if (@atomicLoad(u8, &self.writer_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
173 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
166 if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
167 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) != null) {
174168 // We did not obtain the lock. Great, the queues are someone else's problem.
175169 return;
176170 }
......@@ -180,13 +174,13 @@ pub const RwLock = struct {
180174 return;
181175 }
182176 // Release the lock again.
183 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
184 _ = @atomicRmw(u8, &self.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);
177 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
178 _ = @atomicRmw(u8, &self.shared_state, .Xchg, State.Unlocked, .SeqCst);
185179 continue;
186180 }
187181
188 if (@atomicLoad(u8, &self.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
189 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
182 if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
183 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst) != null) {
190184 // We did not obtain the lock. Great, the queues are someone else's problem.
191185 return;
192186 }
......@@ -199,8 +193,8 @@ pub const RwLock = struct {
199193 return;
200194 }
201195 // Release the lock again.
202 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
203 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
196 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
197 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
204198 // Didn't unlock. Someone else's problem.
205199 return;
206200 }
......@@ -215,6 +209,9 @@ test "std.event.RwLock" {
215209 // https://github.com/ziglang/zig/issues/2377
216210 if (true) return error.SkipZigTest;
217211
212 // https://github.com/ziglang/zig/issues/1908
213 if (builtin.single_threaded) return error.SkipZigTest;
214
218215 const allocator = std.heap.direct_allocator;
219216
220217 var loop: Loop = undefined;
......@@ -224,8 +221,7 @@ test "std.event.RwLock" {
224221 var lock = RwLock.init(&loop);
225222 defer lock.deinit();
226223
227 const handle = try async<allocator> testLock(&loop, &lock);
228 defer cancel handle;
224 const handle = testLock(&loop, &lock);
229225 loop.run();
230226
231227 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
......@@ -233,28 +229,31 @@ test "std.event.RwLock" {
233229}
234230
235231async fn testLock(loop: *Loop, lock: *RwLock) void {
236 // TODO explicitly put next tick node memory in the coroutine frame #1194
237 suspend {
238 resume @handle();
239 }
240
241232 var read_nodes: [100]Loop.NextTickNode = undefined;
242233 for (read_nodes) |*read_node| {
243 read_node.data = async readRunner(lock) catch @panic("out of memory");
234 const frame = loop.allocator.create(@Frame(readRunner)) catch @panic("memory");
235 read_node.data = frame;
236 frame.* = async readRunner(lock);
244237 loop.onNextTick(read_node);
245238 }
246239
247240 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;
248241 for (write_nodes) |*write_node| {
249 write_node.data = async writeRunner(lock) catch @panic("out of memory");
242 const frame = loop.allocator.create(@Frame(writeRunner)) catch @panic("memory");
243 write_node.data = frame;
244 frame.* = async writeRunner(lock);
250245 loop.onNextTick(write_node);
251246 }
252247
253248 for (write_nodes) |*write_node| {
254 await @ptrCast(promise->void, write_node.data);
249 const casted = @ptrCast(*const @Frame(writeRunner), write_node.data);
250 await casted;
251 loop.allocator.destroy(casted);
255252 }
256253 for (read_nodes) |*read_node| {
257 await @ptrCast(promise->void, read_node.data);
254 const casted = @ptrCast(*const @Frame(readRunner), read_node.data);
255 await casted;
256 loop.allocator.destroy(casted);
258257 }
259258}
260259
......@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {
269268 var i: usize = 0;
270269 while (i < shared_test_data.len) : (i += 1) {
271270 std.time.sleep(100 * std.time.microsecond);
272 const lock_promise = async lock.acquireWrite() catch @panic("out of memory");
271 const lock_promise = async lock.acquireWrite();
273272 const handle = await lock_promise;
274273 defer handle.release();
275274
......@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {
287286
288287 var i: usize = 0;
289288 while (i < shared_test_data.len) : (i += 1) {
290 const lock_promise = async lock.acquireRead() catch @panic("out of memory");
289 const lock_promise = async lock.acquireRead();
291290 const handle = await lock_promise;
292291 defer handle.release();
293292
std/event/rwlocked.zig+1-1
......@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;
33const Loop = std.event.Loop;
44
55/// Thread-safe async/await RW lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and
6/// Functions which are waiting for the lock are suspended, and
77/// are resumed when the lock is released, in order.
88pub fn RwLocked(comptime T: type) type {
99 return struct {
std/fmt.zig-3
......@@ -328,9 +328,6 @@ pub fn formatType(
328328 try output(context, "error.");
329329 return output(context, @errorName(value));
330330 },
331 .Promise => {
332 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
333 },
334331 .Enum => {
335332 if (comptime std.meta.trait.hasFn("format")(T)) {
336333 return value.format(fmt, options, context, Errors, output);
std/hash/auto_hash.zig+25-24
......@@ -8,31 +8,32 @@ const meta = std.meta;
88pub fn autoHash(hasher: var, key: var) void {
99 const Key = @typeOf(key);
1010 switch (@typeInfo(Key)) {
11 builtin.TypeId.NoReturn,
12 builtin.TypeId.Opaque,
13 builtin.TypeId.Undefined,
14 builtin.TypeId.ArgTuple,
15 builtin.TypeId.Void,
16 builtin.TypeId.Null,
17 builtin.TypeId.BoundFn,
18 builtin.TypeId.ComptimeFloat,
19 builtin.TypeId.ComptimeInt,
20 builtin.TypeId.Type,
21 builtin.TypeId.EnumLiteral,
11 .NoReturn,
12 .Opaque,
13 .Undefined,
14 .ArgTuple,
15 .Void,
16 .Null,
17 .BoundFn,
18 .ComptimeFloat,
19 .ComptimeInt,
20 .Type,
21 .EnumLiteral,
22 .Frame,
2223 => @compileError("cannot hash this type"),
2324
2425 // Help the optimizer see that hashing an int is easy by inlining!
2526 // TODO Check if the situation is better after #561 is resolved.
26 builtin.TypeId.Int => @inlineCall(hasher.update, std.mem.asBytes(&key)),
27 .Int => @inlineCall(hasher.update, std.mem.asBytes(&key)),
2728
28 builtin.TypeId.Float => |info| autoHash(hasher, @bitCast(@IntType(false, info.bits), key)),
29 .Float => |info| autoHash(hasher, @bitCast(@IntType(false, info.bits), key)),
2930
30 builtin.TypeId.Bool => autoHash(hasher, @boolToInt(key)),
31 builtin.TypeId.Enum => autoHash(hasher, @enumToInt(key)),
32 builtin.TypeId.ErrorSet => autoHash(hasher, @errorToInt(key)),
33 builtin.TypeId.Promise, builtin.TypeId.Fn => autoHash(hasher, @ptrToInt(key)),
31 .Bool => autoHash(hasher, @boolToInt(key)),
32 .Enum => autoHash(hasher, @enumToInt(key)),
33 .ErrorSet => autoHash(hasher, @errorToInt(key)),
34 .AnyFrame, .Fn => autoHash(hasher, @ptrToInt(key)),
3435
35 builtin.TypeId.Pointer => |info| switch (info.size) {
36 .Pointer => |info| switch (info.size) {
3637 builtin.TypeInfo.Pointer.Size.One,
3738 builtin.TypeInfo.Pointer.Size.Many,
3839 builtin.TypeInfo.Pointer.Size.C,
......@@ -44,9 +45,9 @@ pub fn autoHash(hasher: var, key: var) void {
4445 },
4546 },
4647
47 builtin.TypeId.Optional => if (key) |k| autoHash(hasher, k),
48 .Optional => if (key) |k| autoHash(hasher, k),
4849
49 builtin.TypeId.Array => {
50 .Array => {
5051 // TODO detect via a trait when Key has no padding bits to
5152 // hash it as an array of bytes.
5253 // Otherwise, hash every element.
......@@ -55,7 +56,7 @@ pub fn autoHash(hasher: var, key: var) void {
5556 }
5657 },
5758
58 builtin.TypeId.Vector => |info| {
59 .Vector => |info| {
5960 if (info.child.bit_count % 8 == 0) {
6061 // If there's no unused bits in the child type, we can just hash
6162 // this as an array of bytes.
......@@ -71,7 +72,7 @@ pub fn autoHash(hasher: var, key: var) void {
7172 }
7273 },
7374
74 builtin.TypeId.Struct => |info| {
75 .Struct => |info| {
7576 // TODO detect via a trait when Key has no padding bits to
7677 // hash it as an array of bytes.
7778 // Otherwise, hash every field.
......@@ -82,7 +83,7 @@ pub fn autoHash(hasher: var, key: var) void {
8283 }
8384 },
8485
85 builtin.TypeId.Union => |info| blk: {
86 .Union => |info| blk: {
8687 if (info.tag_type) |tag_type| {
8788 const tag = meta.activeTag(key);
8889 const s = autoHash(hasher, tag);
......@@ -99,7 +100,7 @@ pub fn autoHash(hasher: var, key: var) void {
99100 } else @compileError("cannot hash untagged union type: " ++ @typeName(Key) ++ ", provide your own hash function");
100101 },
101102
102 builtin.TypeId.ErrorUnion => blk: {
103 .ErrorUnion => blk: {
103104 const payload = key catch |err| {
104105 autoHash(hasher, err);
105106 break :blk;
std/meta.zig+1-3
......@@ -104,8 +104,7 @@ pub fn Child(comptime T: type) type {
104104 TypeId.Array => |info| info.child,
105105 TypeId.Pointer => |info| info.child,
106106 TypeId.Optional => |info| info.child,
107 TypeId.Promise => |info| if (info.child) |child| child else null,
108 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
109108 };
110109}
111110
......@@ -114,7 +113,6 @@ test "std.meta.Child" {
114113 testing.expect(Child(*u8) == u8);
115114 testing.expect(Child([]u8) == u8);
116115 testing.expect(Child(?u8) == u8);
117 testing.expect(Child(promise->u8) == u8);
118116}
119117
120118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
std/testing.zig+26-25
......@@ -25,36 +25,37 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
2525/// The types must match exactly.
2626pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
2727 switch (@typeInfo(@typeOf(actual))) {
28 TypeId.NoReturn,
29 TypeId.BoundFn,
30 TypeId.ArgTuple,
31 TypeId.Opaque,
28 .NoReturn,
29 .BoundFn,
30 .ArgTuple,
31 .Opaque,
32 .Frame,
33 .AnyFrame,
3234 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
3335
34 TypeId.Undefined,
35 TypeId.Null,
36 TypeId.Void,
36 .Undefined,
37 .Null,
38 .Void,
3739 => return,
3840
39 TypeId.Type,
40 TypeId.Bool,
41 TypeId.Int,
42 TypeId.Float,
43 TypeId.ComptimeFloat,
44 TypeId.ComptimeInt,
45 TypeId.EnumLiteral,
46 TypeId.Enum,
47 TypeId.Fn,
48 TypeId.Promise,
49 TypeId.Vector,
50 TypeId.ErrorSet,
41 .Type,
42 .Bool,
43 .Int,
44 .Float,
45 .ComptimeFloat,
46 .ComptimeInt,
47 .EnumLiteral,
48 .Enum,
49 .Fn,
50 .Vector,
51 .ErrorSet,
5152 => {
5253 if (actual != expected) {
5354 std.debug.panic("expected {}, found {}", expected, actual);
5455 }
5556 },
5657
57 TypeId.Pointer => |pointer| {
58 .Pointer => |pointer| {
5859 switch (pointer.size) {
5960 builtin.TypeInfo.Pointer.Size.One,
6061 builtin.TypeInfo.Pointer.Size.Many,
......@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
7677 }
7778 },
7879
79 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),
80 .Array => |array| expectEqualSlices(array.child, &expected, &actual),
8081
81 TypeId.Struct => |structType| {
82 .Struct => |structType| {
8283 inline for (structType.fields) |field| {
8384 expectEqual(@field(expected, field.name), @field(actual, field.name));
8485 }
8586 },
8687
87 TypeId.Union => |union_info| {
88 .Union => |union_info| {
8889 if (union_info.tag_type == null) {
8990 @compileError("Unable to compare untagged union values");
9091 }
9192 @compileError("TODO implement testing.expectEqual for tagged unions");
9293 },
9394
94 TypeId.Optional => {
95 .Optional => {
9596 if (expected) |expected_payload| {
9697 if (actual) |actual_payload| {
9798 expectEqual(expected_payload, actual_payload);
......@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
105106 }
106107 },
107108
108 TypeId.ErrorUnion => {
109 .ErrorUnion => {
109110 if (expected) |expected_payload| {
110111 if (actual) |actual_payload| {
111112 expectEqual(expected_payload, actual_payload);
std/zig/ast.zig+8-8
......@@ -400,7 +400,7 @@ pub const Node = struct {
400400 VarType,
401401 ErrorType,
402402 FnProto,
403 PromiseType,
403 AnyFrameType,
404404
405405 // Primary expressions
406406 IntegerLiteral,
......@@ -952,9 +952,9 @@ pub const Node = struct {
952952 }
953953 };
954954
955 pub const PromiseType = struct {
955 pub const AnyFrameType = struct {
956956 base: Node,
957 promise_token: TokenIndex,
957 anyframe_token: TokenIndex,
958958 result: ?Result,
959959
960960 pub const Result = struct {
......@@ -962,7 +962,7 @@ pub const Node = struct {
962962 return_type: *Node,
963963 };
964964
965 pub fn iterate(self: *PromiseType, index: usize) ?*Node {
965 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
966966 var i = index;
967967
968968 if (self.result) |result| {
......@@ -973,13 +973,13 @@ pub const Node = struct {
973973 return null;
974974 }
975975
976 pub fn firstToken(self: *const PromiseType) TokenIndex {
977 return self.promise_token;
976 pub fn firstToken(self: *const AnyFrameType) TokenIndex {
977 return self.anyframe_token;
978978 }
979979
980 pub fn lastToken(self: *const PromiseType) TokenIndex {
980 pub fn lastToken(self: *const AnyFrameType) TokenIndex {
981981 if (self.result) |result| return result.return_type.lastToken();
982 return self.promise_token;
982 return self.anyframe_token;
983983 }
984984 };
985985
std/zig/parse.zig+20-35
......@@ -814,7 +814,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
814814/// <- AsmExpr
815815/// / IfExpr
816816/// / KEYWORD_break BreakLabel? Expr?
817/// / KEYWORD_cancel Expr
818817/// / KEYWORD_comptime Expr
819818/// / KEYWORD_continue BreakLabel?
820819/// / KEYWORD_resume Expr
......@@ -839,20 +838,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
839838 return &node.base;
840839 }
841840
842 if (eatToken(it, .Keyword_cancel)) |token| {
843 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
844 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
845 });
846 const node = try arena.create(Node.PrefixOp);
847 node.* = Node.PrefixOp{
848 .base = Node{ .id = .PrefixOp },
849 .op_token = token,
850 .op = Node.PrefixOp.Op.Cancel,
851 .rhs = expr_node,
852 };
853 return &node.base;
854 }
855
856841 if (eatToken(it, .Keyword_comptime)) |token| {
857842 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
858843 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
......@@ -1201,7 +1186,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
12011186/// / KEYWORD_error DOT IDENTIFIER
12021187/// / KEYWORD_false
12031188/// / KEYWORD_null
1204/// / KEYWORD_promise
1189/// / KEYWORD_anyframe
12051190/// / KEYWORD_true
12061191/// / KEYWORD_undefined
12071192/// / KEYWORD_unreachable
......@@ -1256,11 +1241,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
12561241 }
12571242 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
12581243 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1259 if (eatToken(it, .Keyword_promise)) |token| {
1260 const node = try arena.create(Node.PromiseType);
1261 node.* = Node.PromiseType{
1262 .base = Node{ .id = .PromiseType },
1263 .promise_token = token,
1244 if (eatToken(it, .Keyword_anyframe)) |token| {
1245 const node = try arena.create(Node.AnyFrameType);
1246 node.* = Node.AnyFrameType{
1247 .base = Node{ .id = .AnyFrameType },
1248 .anyframe_token = token,
12641249 .result = null,
12651250 };
12661251 return &node.base;
......@@ -2194,7 +2179,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
21942179
21952180/// PrefixTypeOp
21962181/// <- QUESTIONMARK
2197/// / KEYWORD_promise MINUSRARROW
2182/// / KEYWORD_anyframe MINUSRARROW
21982183/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
21992184/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
22002185fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
......@@ -2209,20 +2194,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
22092194 return &node.base;
22102195 }
22112196
2212 // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or
2197 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
22132198 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2214 // Consider making the PromiseType a member of PrefixOp and add a
2215 // PrefixOp.PromiseType variant?
2216 if (eatToken(it, .Keyword_promise)) |token| {
2199 // Consider making the AnyFrameType a member of PrefixOp and add a
2200 // PrefixOp.AnyFrameType variant?
2201 if (eatToken(it, .Keyword_anyframe)) |token| {
22172202 const arrow = eatToken(it, .Arrow) orelse {
22182203 putBackToken(it, token);
22192204 return null;
22202205 };
2221 const node = try arena.create(Node.PromiseType);
2222 node.* = Node.PromiseType{
2223 .base = Node{ .id = .PromiseType },
2224 .promise_token = token,
2225 .result = Node.PromiseType.Result{
2206 const node = try arena.create(Node.AnyFrameType);
2207 node.* = Node.AnyFrameType{
2208 .base = Node{ .id = .AnyFrameType },
2209 .anyframe_token = token,
2210 .result = Node.AnyFrameType.Result{
22262211 .arrow_token = arrow,
22272212 .return_type = undefined, // set by caller
22282213 },
......@@ -2903,8 +2888,8 @@ fn parsePrefixOpExpr(
29032888 rightmost_op = rhs;
29042889 } else break;
29052890 },
2906 .PromiseType => {
2907 const prom = rightmost_op.cast(Node.PromiseType).?;
2891 .AnyFrameType => {
2892 const prom = rightmost_op.cast(Node.AnyFrameType).?;
29082893 if (try opParseFn(arena, it, tree)) |rhs| {
29092894 prom.result.?.return_type = rhs;
29102895 rightmost_op = rhs;
......@@ -2922,8 +2907,8 @@ fn parsePrefixOpExpr(
29222907 .InvalidToken = AstError.InvalidToken{ .token = it.index },
29232908 });
29242909 },
2925 .PromiseType => {
2926 const prom = rightmost_op.cast(Node.PromiseType).?;
2910 .AnyFrameType => {
2911 const prom = rightmost_op.cast(Node.AnyFrameType).?;
29272912 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
29282913 .InvalidToken = AstError.InvalidToken{ .token = it.index },
29292914 });
std/zig/parser_test.zig+6-6
......@@ -1183,7 +1183,7 @@ test "zig fmt: resume from suspend block" {
11831183 try testCanonical(
11841184 \\fn foo() void {
11851185 \\ suspend {
1186 \\ resume @handle();
1186 \\ resume @frame();
11871187 \\ }
11881188 \\}
11891189 \\
......@@ -2103,7 +2103,7 @@ test "zig fmt: inline asm" {
21032103 );
21042104}
21052105
2106test "zig fmt: coroutines" {
2106test "zig fmt: async functions" {
21072107 try testCanonical(
21082108 \\async fn simpleAsyncFn() void {
21092109 \\ const a = async a.b();
......@@ -2111,14 +2111,14 @@ test "zig fmt: coroutines" {
21112111 \\ suspend;
21122112 \\ x += 1;
21132113 \\ suspend;
2114 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;
2114 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
21152115 \\ await p;
21162116 \\}
21172117 \\
2118 \\test "coroutine suspend, resume, cancel" {
2119 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();
2118 \\test "suspend, resume, await" {
2119 \\ const p: anyframe = async testAsyncSeq();
21202120 \\ resume p;
2121 \\ cancel p;
2121 \\ await p;
21222122 \\}
21232123 \\
21242124 );
std/zig/render.zig+5-5
......@@ -1205,15 +1205,15 @@ fn renderExpression(
12051205 }
12061206 },
12071207
1208 ast.Node.Id.PromiseType => {
1209 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
1208 ast.Node.Id.AnyFrameType => {
1209 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
12101210
1211 if (promise_type.result) |result| {
1212 try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise
1211 if (anyframe_type.result) |result| {
1212 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
12131213 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
12141214 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
12151215 } else {
1216 return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise
1216 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
12171217 }
12181218 },
12191219
std/zig/tokenizer.zig+2-4
......@@ -15,12 +15,12 @@ pub const Token = struct {
1515 Keyword{ .bytes = "align", .id = Id.Keyword_align },
1616 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
1717 Keyword{ .bytes = "and", .id = Id.Keyword_and },
18 Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
1819 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
1920 Keyword{ .bytes = "async", .id = Id.Keyword_async },
2021 Keyword{ .bytes = "await", .id = Id.Keyword_await },
2122 Keyword{ .bytes = "break", .id = Id.Keyword_break },
2223 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
23 Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel },
2424 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
2525 Keyword{ .bytes = "const", .id = Id.Keyword_const },
2626 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
......@@ -42,7 +42,6 @@ pub const Token = struct {
4242 Keyword{ .bytes = "or", .id = Id.Keyword_or },
4343 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
4444 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
45 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
4645 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
4746 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
4847 Keyword{ .bytes = "return", .id = Id.Keyword_return },
......@@ -151,7 +150,6 @@ pub const Token = struct {
151150 Keyword_async,
152151 Keyword_await,
153152 Keyword_break,
154 Keyword_cancel,
155153 Keyword_catch,
156154 Keyword_comptime,
157155 Keyword_const,
......@@ -174,7 +172,7 @@ pub const Token = struct {
174172 Keyword_or,
175173 Keyword_orelse,
176174 Keyword_packed,
177 Keyword_promise,
175 Keyword_anyframe,
178176 Keyword_pub,
179177 Keyword_resume,
180178 Keyword_return,
test/compile_errors.zig+122-27
......@@ -2,6 +2,118 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "@frame() causes function to be async",
7 \\export fn entry() void {
8 \\ func();
9 \\}
10 \\fn func() void {
11 \\ _ = @frame();
12 \\}
13 ,
14 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
15 "tmp.zig:5:9: note: @frame() causes function to be async",
16 );
17 cases.add(
18 "invalid suspend in exported function",
19 \\export fn entry() void {
20 \\ var frame = async func();
21 \\ var result = await frame;
22 \\}
23 \\fn func() void {
24 \\ suspend;
25 \\}
26 ,
27 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
28 "tmp.zig:3:18: note: await is a suspend point",
29 );
30
31 cases.add(
32 "async function indirectly depends on its own frame",
33 \\export fn entry() void {
34 \\ _ = async amain();
35 \\}
36 \\async fn amain() void {
37 \\ other();
38 \\}
39 \\fn other() void {
40 \\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
41 \\}
42 ,
43 "tmp.zig:4:1: error: unable to determine async function frame of 'amain'",
44 "tmp.zig:5:10: note: analysis of function 'other' depends on the frame",
45 "tmp.zig:8:13: note: depends on the frame here",
46 );
47
48 cases.add(
49 "async function depends on its own frame",
50 \\export fn entry() void {
51 \\ _ = async amain();
52 \\}
53 \\async fn amain() void {
54 \\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
55 \\}
56 ,
57 "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet",
58 "tmp.zig:5:13: note: depends on its own frame here",
59 );
60
61 cases.add(
62 "non async function pointer passed to @asyncCall",
63 \\export fn entry() void {
64 \\ var ptr = afunc;
65 \\ var bytes: [100]u8 = undefined;
66 \\ _ = @asyncCall(&bytes, {}, ptr);
67 \\}
68 \\fn afunc() void { }
69 ,
70 "tmp.zig:4:32: error: expected async function, found 'fn() void'",
71 );
72
73 cases.add(
74 "runtime-known async function called",
75 \\export fn entry() void {
76 \\ _ = async amain();
77 \\}
78 \\fn amain() void {
79 \\ var ptr = afunc;
80 \\ _ = ptr();
81 \\}
82 \\async fn afunc() void {}
83 ,
84 "tmp.zig:6:12: error: function is not comptime-known; @asyncCall required",
85 );
86
87 cases.add(
88 "runtime-known function called with async keyword",
89 \\export fn entry() void {
90 \\ var ptr = afunc;
91 \\ _ = async ptr();
92 \\}
93 \\
94 \\async fn afunc() void { }
95 ,
96 "tmp.zig:3:15: error: function is not comptime-known; @asyncCall required",
97 );
98
99 cases.add(
100 "function with ccc indirectly calling async function",
101 \\export fn entry() void {
102 \\ foo();
103 \\}
104 \\fn foo() void {
105 \\ bar();
106 \\}
107 \\fn bar() void {
108 \\ suspend;
109 \\}
110 ,
111 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
112 "tmp.zig:2:8: note: async function call here",
113 "tmp.zig:5:8: note: async function call here",
114 "tmp.zig:8:5: note: suspends here",
115 );
116
5117 cases.add(
6118 "capture group on switch prong with incompatible payload types",
7119 \\const Union = union(enum) {
......@@ -1319,24 +1431,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13191431 );
13201432
13211433 cases.add(
1322 "@handle() called outside of function definition",
1323 \\var handle_undef: promise = undefined;
1324 \\var handle_dummy: promise = @handle();
1434 "@frame() called outside of function definition",
1435 \\var handle_undef: anyframe = undefined;
1436 \\var handle_dummy: anyframe = @frame();
13251437 \\export fn entry() bool {
13261438 \\ return handle_undef == handle_dummy;
13271439 \\}
13281440 ,
1329 "tmp.zig:2:29: error: @handle() called outside of function definition",
1330 );
1331
1332 cases.add(
1333 "@handle() in non-async function",
1334 \\export fn entry() bool {
1335 \\ var handle_undef: promise = undefined;
1336 \\ return handle_undef == @handle();
1337 \\}
1338 ,
1339 "tmp.zig:3:28: error: @handle() in non-async function",
1441 "tmp.zig:2:30: error: @frame() called outside of function definition",
13401442 );
13411443
13421444 cases.add(
......@@ -1712,15 +1814,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17121814
17131815 cases.add(
17141816 "suspend inside suspend block",
1715 \\const std = @import("std",);
1716 \\
17171817 \\export fn entry() void {
1718 \\ var buf: [500]u8 = undefined;
1719 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
1720 \\ const p = (async<a> foo()) catch unreachable;
1721 \\ cancel p;
1818 \\ _ = async foo();
17221819 \\}
1723 \\
17241820 \\async fn foo() void {
17251821 \\ suspend {
17261822 \\ suspend {
......@@ -1728,8 +1824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17281824 \\ }
17291825 \\}
17301826 ,
1731 "tmp.zig:12:9: error: cannot suspend inside suspend block",
1732 "tmp.zig:11:5: note: other suspend block here",
1827 "tmp.zig:6:9: error: cannot suspend inside suspend block",
1828 "tmp.zig:5:5: note: other suspend block here",
17331829 );
17341830
17351831 cases.add(
......@@ -1770,15 +1866,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17701866
17711867 cases.add(
17721868 "returning error from void async function",
1773 \\const std = @import("std",);
17741869 \\export fn entry() void {
1775 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;
1870 \\ _ = async amain();
17761871 \\}
17771872 \\async fn amain() void {
17781873 \\ return error.ShouldBeCompileError;
17791874 \\}
17801875 ,
1781 "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
1876 "tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
17821877 );
17831878
17841879 cases.add(
......@@ -3307,7 +3402,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33073402 \\
33083403 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
33093404 ,
3310 "tmp.zig:5:18: error: unable to evaluate constant expression",
3405 "tmp.zig:5:25: error: unable to evaluate constant expression",
33113406 "tmp.zig:2:12: note: called from here",
33123407 "tmp.zig:2:8: note: called from here",
33133408 );
test/runtime_safety.zig+96-5
......@@ -1,6 +1,91 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("awaiting twice",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\var frame: anyframe = undefined;
9 \\
10 \\pub fn main() void {
11 \\ _ = async amain();
12 \\ resume frame;
13 \\}
14 \\
15 \\fn amain() void {
16 \\ var f = async func();
17 \\ await f;
18 \\ await f;
19 \\}
20 \\
21 \\fn func() void {
22 \\ suspend {
23 \\ frame = @frame();
24 \\ }
25 \\}
26 );
27
28 cases.addRuntimeSafety("@asyncCall with too small a frame",
29 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
30 \\ @import("std").os.exit(126);
31 \\}
32 \\pub fn main() void {
33 \\ var bytes: [1]u8 = undefined;
34 \\ var ptr = other;
35 \\ var frame = @asyncCall(&bytes, {}, ptr);
36 \\}
37 \\async fn other() void {
38 \\ suspend;
39 \\}
40 );
41
42 cases.addRuntimeSafety("resuming a function which is awaiting a frame",
43 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
44 \\ @import("std").os.exit(126);
45 \\}
46 \\pub fn main() void {
47 \\ var frame = async first();
48 \\ resume frame;
49 \\}
50 \\fn first() void {
51 \\ var frame = async other();
52 \\ await frame;
53 \\}
54 \\fn other() void {
55 \\ suspend;
56 \\}
57 );
58
59 cases.addRuntimeSafety("resuming a function which is awaiting a call",
60 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
61 \\ @import("std").os.exit(126);
62 \\}
63 \\pub fn main() void {
64 \\ var frame = async first();
65 \\ resume frame;
66 \\}
67 \\fn first() void {
68 \\ other();
69 \\}
70 \\fn other() void {
71 \\ suspend;
72 \\}
73 );
74
75 cases.addRuntimeSafety("invalid resume of async function",
76 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
77 \\ @import("std").os.exit(126);
78 \\}
79 \\pub fn main() void {
80 \\ var p = async suspendOnce();
81 \\ resume p; //ok
82 \\ resume p; //bad
83 \\}
84 \\fn suspendOnce() void {
85 \\ suspend;
86 \\}
87 );
88
489 cases.addRuntimeSafety(".? operator on null pointer",
590 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
691 \\ @import("std").os.exit(126);
......@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
483568 \\ std.os.exit(126);
484569 \\}
485570 \\
571 \\var failing_frame: @Frame(failing) = undefined;
572 \\
486573 \\pub fn main() void {
487574 \\ const p = nonFailing();
488575 \\ resume p;
489 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;
490 \\ cancel p2;
576 \\ const p2 = async printTrace(p);
491577 \\}
492578 \\
493 \\fn nonFailing() promise->anyerror!void {
494 \\ return async<std.debug.global_allocator> failing() catch unreachable;
579 \\fn nonFailing() anyframe->anyerror!void {
580 \\ failing_frame = async failing();
581 \\ return &failing_frame;
495582 \\}
496583 \\
497584 \\async fn failing() anyerror!void {
498585 \\ suspend;
586 \\ return second();
587 \\}
588 \\
589 \\async fn second() anyerror!void {
499590 \\ return error.Fail;
500591 \\}
501592 \\
502 \\async fn printTrace(p: promise->anyerror!void) void {
593 \\async fn printTrace(p: anyframe->anyerror!void) void {
503594 \\ (await p) catch unreachable;
504595 \\}
505596 );
test/stage1/behavior.zig+6-7
......@@ -3,12 +3,13 @@ comptime {
33 _ = @import("behavior/alignof.zig");
44 _ = @import("behavior/array.zig");
55 _ = @import("behavior/asm.zig");
6 _ = @import("behavior/async_fn.zig");
67 _ = @import("behavior/atomics.zig");
8 _ = @import("behavior/await_struct.zig");
79 _ = @import("behavior/bit_shifting.zig");
810 _ = @import("behavior/bitcast.zig");
911 _ = @import("behavior/bitreverse.zig");
1012 _ = @import("behavior/bool.zig");
11 _ = @import("behavior/byteswap.zig");
1213 _ = @import("behavior/bugs/1025.zig");
1314 _ = @import("behavior/bugs/1076.zig");
1415 _ = @import("behavior/bugs/1111.zig");
......@@ -38,23 +39,23 @@ comptime {
3839 _ = @import("behavior/bugs/726.zig");
3940 _ = @import("behavior/bugs/828.zig");
4041 _ = @import("behavior/bugs/920.zig");
42 _ = @import("behavior/byteswap.zig");
4143 _ = @import("behavior/byval_arg_var.zig");
42 _ = @import("behavior/cancel.zig");
4344 _ = @import("behavior/cast.zig");
4445 _ = @import("behavior/const_slice_child.zig");
45 _ = @import("behavior/coroutine_await_struct.zig");
46 _ = @import("behavior/coroutines.zig");
4746 _ = @import("behavior/defer.zig");
4847 _ = @import("behavior/enum.zig");
4948 _ = @import("behavior/enum_with_members.zig");
5049 _ = @import("behavior/error.zig");
5150 _ = @import("behavior/eval.zig");
5251 _ = @import("behavior/field_parent_ptr.zig");
52 _ = @import("behavior/floatop.zig");
5353 _ = @import("behavior/fn.zig");
5454 _ = @import("behavior/fn_in_struct_in_comptime.zig");
5555 _ = @import("behavior/for.zig");
5656 _ = @import("behavior/generics.zig");
5757 _ = @import("behavior/hasdecl.zig");
58 _ = @import("behavior/hasfield.zig");
5859 _ = @import("behavior/if.zig");
5960 _ = @import("behavior/import.zig");
6061 _ = @import("behavior/incomplete_struct_param_tld.zig");
......@@ -63,14 +64,13 @@ comptime {
6364 _ = @import("behavior/math.zig");
6465 _ = @import("behavior/merge_error_sets.zig");
6566 _ = @import("behavior/misc.zig");
67 _ = @import("behavior/muladd.zig");
6668 _ = @import("behavior/namespace_depends_on_compile_var.zig");
6769 _ = @import("behavior/new_stack_call.zig");
6870 _ = @import("behavior/null.zig");
6971 _ = @import("behavior/optional.zig");
7072 _ = @import("behavior/pointers.zig");
7173 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
7474 _ = @import("behavior/ptrcast.zig");
7575 _ = @import("behavior/pub_enum.zig");
7676 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
......@@ -99,5 +99,4 @@ comptime {
9999 _ = @import("behavior/void.zig");
100100 _ = @import("behavior/while.zig");
101101 _ = @import("behavior/widening.zig");
102 _ = @import("behavior/hasfield.zig");
103102}
test/stage1/behavior/align.zig+62
......@@ -228,3 +228,65 @@ test "alignment of extern() void" {
228228}
229229
230230extern fn nothing() void {}
231
232test "return error union with 128-bit integer" {
233 expect(3 == try give());
234}
235fn give() anyerror!u128 {
236 return 3;
237}
238
239test "alignment of >= 128-bit integer type" {
240 expect(@alignOf(u128) == 16);
241 expect(@alignOf(u129) == 16);
242}
243
244test "alignment of struct with 128-bit field" {
245 expect(@alignOf(struct {
246 x: u128,
247 }) == 16);
248
249 comptime {
250 expect(@alignOf(struct {
251 x: u128,
252 }) == 16);
253 }
254}
255
256test "size of extern struct with 128-bit field" {
257 expect(@sizeOf(extern struct {
258 x: u128,
259 y: u8,
260 }) == 32);
261
262 comptime {
263 expect(@sizeOf(extern struct {
264 x: u128,
265 y: u8,
266 }) == 32);
267 }
268}
269
270const DefaultAligned = struct {
271 nevermind: u32,
272 badguy: i128,
273};
274
275test "read 128-bit field from default aligned struct in stack memory" {
276 var default_aligned = DefaultAligned{
277 .nevermind = 1,
278 .badguy = 12,
279 };
280 expect((@ptrToInt(&default_aligned.badguy) % 16) == 0);
281 expect(12 == default_aligned.badguy);
282}
283
284var default_aligned_global = DefaultAligned{
285 .nevermind = 1,
286 .badguy = 12,
287};
288
289test "read 128-bit field from default aligned struct in global memory" {
290 expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0);
291 expect(12 == default_aligned_global.badguy);
292}
test/stage1/behavior/async_fn.zig created+736
......@@ -0,0 +1,736 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5
6var global_x: i32 = 1;
7
8test "simple coroutine suspend and resume" {
9 const frame = async simpleAsyncFn();
10 expect(global_x == 2);
11 resume frame;
12 expect(global_x == 3);
13 const af: anyframe->void = &frame;
14 resume frame;
15 expect(global_x == 4);
16}
17fn simpleAsyncFn() void {
18 global_x += 1;
19 suspend;
20 global_x += 1;
21 suspend;
22 global_x += 1;
23}
24
25var global_y: i32 = 1;
26
27test "pass parameter to coroutine" {
28 const p = async simpleAsyncFnWithArg(2);
29 expect(global_y == 3);
30 resume p;
31 expect(global_y == 5);
32}
33fn simpleAsyncFnWithArg(delta: i32) void {
34 global_y += delta;
35 suspend;
36 global_y += delta;
37}
38
39test "suspend at end of function" {
40 const S = struct {
41 var x: i32 = 1;
42
43 fn doTheTest() void {
44 expect(x == 1);
45 const p = async suspendAtEnd();
46 expect(x == 2);
47 }
48
49 fn suspendAtEnd() void {
50 x += 1;
51 suspend;
52 }
53 };
54 S.doTheTest();
55}
56
57test "local variable in async function" {
58 const S = struct {
59 var x: i32 = 0;
60
61 fn doTheTest() void {
62 expect(x == 0);
63 const p = async add(1, 2);
64 expect(x == 0);
65 resume p;
66 expect(x == 0);
67 resume p;
68 expect(x == 0);
69 resume p;
70 expect(x == 3);
71 }
72
73 fn add(a: i32, b: i32) void {
74 var accum: i32 = 0;
75 suspend;
76 accum += a;
77 suspend;
78 accum += b;
79 suspend;
80 x = accum;
81 }
82 };
83 S.doTheTest();
84}
85
86test "calling an inferred async function" {
87 const S = struct {
88 var x: i32 = 1;
89 var other_frame: *@Frame(other) = undefined;
90
91 fn doTheTest() void {
92 _ = async first();
93 expect(x == 1);
94 resume other_frame.*;
95 expect(x == 2);
96 }
97
98 fn first() void {
99 other();
100 }
101 fn other() void {
102 other_frame = @frame();
103 suspend;
104 x += 1;
105 }
106 };
107 S.doTheTest();
108}
109
110test "@frameSize" {
111 const S = struct {
112 fn doTheTest() void {
113 {
114 var ptr = @ptrCast(async fn(i32) void, other);
115 const size = @frameSize(ptr);
116 expect(size == @sizeOf(@Frame(other)));
117 }
118 {
119 var ptr = @ptrCast(async fn() void, first);
120 const size = @frameSize(ptr);
121 expect(size == @sizeOf(@Frame(first)));
122 }
123 }
124
125 fn first() void {
126 other(1);
127 }
128 fn other(param: i32) void {
129 var local: i32 = undefined;
130 suspend;
131 }
132 };
133 S.doTheTest();
134}
135
136test "coroutine suspend, resume" {
137 const S = struct {
138 var frame: anyframe = undefined;
139
140 fn doTheTest() void {
141 _ = async amain();
142 seq('d');
143 resume frame;
144 seq('h');
145
146 expect(std.mem.eql(u8, points, "abcdefgh"));
147 }
148
149 fn amain() void {
150 seq('a');
151 var f = async testAsyncSeq();
152 seq('c');
153 await f;
154 seq('g');
155 }
156
157 fn testAsyncSeq() void {
158 defer seq('f');
159
160 seq('b');
161 suspend {
162 frame = @frame();
163 }
164 seq('e');
165 }
166 var points = [_]u8{'x'} ** "abcdefgh".len;
167 var index: usize = 0;
168
169 fn seq(c: u8) void {
170 points[index] = c;
171 index += 1;
172 }
173 };
174 S.doTheTest();
175}
176
177test "coroutine suspend with block" {
178 const p = async testSuspendBlock();
179 expect(!global_result);
180 resume a_promise;
181 expect(global_result);
182}
183
184var a_promise: anyframe = undefined;
185var global_result = false;
186async fn testSuspendBlock() void {
187 suspend {
188 comptime expect(@typeOf(@frame()) == *@Frame(testSuspendBlock));
189 a_promise = @frame();
190 }
191
192 // Test to make sure that @frame() works as advertised (issue #1296)
193 // var our_handle: anyframe = @frame();
194 expect(a_promise == anyframe(@frame()));
195
196 global_result = true;
197}
198
199var await_a_promise: anyframe = undefined;
200var await_final_result: i32 = 0;
201
202test "coroutine await" {
203 await_seq('a');
204 const p = async await_amain();
205 await_seq('f');
206 resume await_a_promise;
207 await_seq('i');
208 expect(await_final_result == 1234);
209 expect(std.mem.eql(u8, await_points, "abcdefghi"));
210}
211async fn await_amain() void {
212 await_seq('b');
213 const p = async await_another();
214 await_seq('e');
215 await_final_result = await p;
216 await_seq('h');
217}
218async fn await_another() i32 {
219 await_seq('c');
220 suspend {
221 await_seq('d');
222 await_a_promise = @frame();
223 }
224 await_seq('g');
225 return 1234;
226}
227
228var await_points = [_]u8{0} ** "abcdefghi".len;
229var await_seq_index: usize = 0;
230
231fn await_seq(c: u8) void {
232 await_points[await_seq_index] = c;
233 await_seq_index += 1;
234}
235
236var early_final_result: i32 = 0;
237
238test "coroutine await early return" {
239 early_seq('a');
240 const p = async early_amain();
241 early_seq('f');
242 expect(early_final_result == 1234);
243 expect(std.mem.eql(u8, early_points, "abcdef"));
244}
245async fn early_amain() void {
246 early_seq('b');
247 const p = async early_another();
248 early_seq('d');
249 early_final_result = await p;
250 early_seq('e');
251}
252async fn early_another() i32 {
253 early_seq('c');
254 return 1234;
255}
256
257var early_points = [_]u8{0} ** "abcdef".len;
258var early_seq_index: usize = 0;
259
260fn early_seq(c: u8) void {
261 early_points[early_seq_index] = c;
262 early_seq_index += 1;
263}
264
265test "async function with dot syntax" {
266 const S = struct {
267 var y: i32 = 1;
268 async fn foo() void {
269 y += 1;
270 suspend;
271 }
272 };
273 const p = async S.foo();
274 expect(S.y == 2);
275}
276
277test "async fn pointer in a struct field" {
278 var data: i32 = 1;
279 const Foo = struct {
280 bar: async fn (*i32) void,
281 };
282 var foo = Foo{ .bar = simpleAsyncFn2 };
283 var bytes: [64]u8 = undefined;
284 const f = @asyncCall(&bytes, {}, foo.bar, &data);
285 comptime expect(@typeOf(f) == anyframe->void);
286 expect(data == 2);
287 resume f;
288 expect(data == 4);
289 _ = async doTheAwait(f);
290 expect(data == 4);
291}
292
293fn doTheAwait(f: anyframe->void) void {
294 await f;
295}
296
297async fn simpleAsyncFn2(y: *i32) void {
298 defer y.* += 2;
299 y.* += 1;
300 suspend;
301}
302
303test "@asyncCall with return type" {
304 const Foo = struct {
305 bar: async fn () i32,
306
307 var global_frame: anyframe = undefined;
308
309 async fn middle() i32 {
310 return afunc();
311 }
312
313 fn afunc() i32 {
314 global_frame = @frame();
315 suspend;
316 return 1234;
317 }
318 };
319 var foo = Foo{ .bar = Foo.middle };
320 var bytes: [150]u8 = undefined;
321 var aresult: i32 = 0;
322 _ = @asyncCall(&bytes, &aresult, foo.bar);
323 expect(aresult == 0);
324 resume Foo.global_frame;
325 expect(aresult == 1234);
326}
327
328test "async fn with inferred error set" {
329 const S = struct {
330 var global_frame: anyframe = undefined;
331
332 fn doTheTest() void {
333 var frame: [1]@Frame(middle) = undefined;
334 var result: anyerror!void = undefined;
335 _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle);
336 resume global_frame;
337 std.testing.expectError(error.Fail, result);
338 }
339
340 async fn middle() !void {
341 var f = async middle2();
342 return await f;
343 }
344
345 fn middle2() !void {
346 return failing();
347 }
348
349 fn failing() !void {
350 global_frame = @frame();
351 suspend;
352 return error.Fail;
353 }
354 };
355 S.doTheTest();
356}
357
358test "error return trace across suspend points - early return" {
359 const p = nonFailing();
360 resume p;
361 const p2 = async printTrace(p);
362}
363
364test "error return trace across suspend points - async return" {
365 const p = nonFailing();
366 const p2 = async printTrace(p);
367 resume p;
368}
369
370fn nonFailing() (anyframe->anyerror!void) {
371 const Static = struct {
372 var frame: @Frame(suspendThenFail) = undefined;
373 };
374 Static.frame = async suspendThenFail();
375 return &Static.frame;
376}
377async fn suspendThenFail() anyerror!void {
378 suspend;
379 return error.Fail;
380}
381async fn printTrace(p: anyframe->(anyerror!void)) void {
382 (await p) catch |e| {
383 std.testing.expect(e == error.Fail);
384 if (@errorReturnTrace()) |trace| {
385 expect(trace.index == 1);
386 } else switch (builtin.mode) {
387 .Debug, .ReleaseSafe => @panic("expected return trace"),
388 .ReleaseFast, .ReleaseSmall => {},
389 }
390 };
391}
392
393test "break from suspend" {
394 var my_result: i32 = 1;
395 const p = async testBreakFromSuspend(&my_result);
396 std.testing.expect(my_result == 2);
397}
398async fn testBreakFromSuspend(my_result: *i32) void {
399 suspend {
400 resume @frame();
401 }
402 my_result.* += 1;
403 suspend;
404 my_result.* += 1;
405}
406
407test "heap allocated async function frame" {
408 const S = struct {
409 var x: i32 = 42;
410
411 fn doTheTest() !void {
412 const frame = try std.heap.direct_allocator.create(@Frame(someFunc));
413 defer std.heap.direct_allocator.destroy(frame);
414
415 expect(x == 42);
416 frame.* = async someFunc();
417 expect(x == 43);
418 resume frame;
419 expect(x == 44);
420 }
421
422 fn someFunc() void {
423 x += 1;
424 suspend;
425 x += 1;
426 }
427 };
428 try S.doTheTest();
429}
430
431test "async function call return value" {
432 const S = struct {
433 var frame: anyframe = undefined;
434 var pt = Point{.x = 10, .y = 11 };
435
436 fn doTheTest() void {
437 expectEqual(pt.x, 10);
438 expectEqual(pt.y, 11);
439 _ = async first();
440 expectEqual(pt.x, 10);
441 expectEqual(pt.y, 11);
442 resume frame;
443 expectEqual(pt.x, 1);
444 expectEqual(pt.y, 2);
445 }
446
447 fn first() void {
448 pt = second(1, 2);
449 }
450
451 fn second(x: i32, y: i32) Point {
452 return other(x, y);
453 }
454
455 fn other(x: i32, y: i32) Point {
456 frame = @frame();
457 suspend;
458 return Point{
459 .x = x,
460 .y = y,
461 };
462 }
463
464 const Point = struct {
465 x: i32,
466 y: i32,
467 };
468 };
469 S.doTheTest();
470}
471
472test "suspension points inside branching control flow" {
473 const S = struct {
474 var result: i32 = 10;
475
476 fn doTheTest() void {
477 expect(10 == result);
478 var frame = async func(true);
479 expect(10 == result);
480 resume frame;
481 expect(11 == result);
482 resume frame;
483 expect(12 == result);
484 resume frame;
485 expect(13 == result);
486 }
487
488 fn func(b: bool) void {
489 while (b) {
490 suspend;
491 result += 1;
492 }
493 }
494 };
495 S.doTheTest();
496}
497
498test "call async function which has struct return type" {
499 const S = struct {
500 var frame: anyframe = undefined;
501
502 fn doTheTest() void {
503 _ = async atest();
504 resume frame;
505 }
506
507 fn atest() void {
508 const result = func();
509 expect(result.x == 5);
510 expect(result.y == 6);
511 }
512
513 const Point = struct {
514 x: usize,
515 y: usize,
516 };
517
518 fn func() Point {
519 suspend {
520 frame = @frame();
521 }
522 return Point{
523 .x = 5,
524 .y = 6,
525 };
526 }
527 };
528 S.doTheTest();
529}
530
531test "pass string literal to async function" {
532 const S = struct {
533 var frame: anyframe = undefined;
534 var ok: bool = false;
535
536 fn doTheTest() void {
537 _ = async hello("hello");
538 resume frame;
539 expect(ok);
540 }
541
542 fn hello(msg: []const u8) void {
543 frame = @frame();
544 suspend;
545 expectEqual(([]const u8)("hello"), msg);
546 ok = true;
547 }
548 };
549 S.doTheTest();
550}
551
552test "await inside an errdefer" {
553 const S = struct {
554 var frame: anyframe = undefined;
555
556 fn doTheTest() void {
557 _ = async amainWrap();
558 resume frame;
559 }
560
561 fn amainWrap() !void {
562 var foo = async func();
563 errdefer await foo;
564 return error.Bad;
565 }
566
567 fn func() void {
568 frame = @frame();
569 suspend;
570 }
571
572 };
573 S.doTheTest();
574}
575
576test "try in an async function with error union and non-zero-bit payload" {
577 const S = struct {
578 var frame: anyframe = undefined;
579 var ok = false;
580
581 fn doTheTest() void {
582 _ = async amain();
583 resume frame;
584 expect(ok);
585 }
586
587 fn amain() void {
588 std.testing.expectError(error.Bad, theProblem());
589 ok = true;
590 }
591
592 fn theProblem() ![]u8 {
593 frame = @frame();
594 suspend;
595 const result = try other();
596 return result;
597 }
598
599 fn other() ![]u8 {
600 return error.Bad;
601 }
602 };
603 S.doTheTest();
604}
605
606test "returning a const error from async function" {
607 const S = struct {
608 var frame: anyframe = undefined;
609 var ok = false;
610
611 fn doTheTest() void {
612 _ = async amain();
613 resume frame;
614 expect(ok);
615 }
616
617 fn amain() !void {
618 var download_frame = async fetchUrl(10, "a string");
619 const download_text = try await download_frame;
620
621 @panic("should not get here");
622 }
623
624 fn fetchUrl(unused: i32, url: []const u8) ![]u8 {
625 frame = @frame();
626 suspend;
627 ok = true;
628 return error.OutOfMemory;
629 }
630 };
631 S.doTheTest();
632}
633
634test "async/await typical usage" {
635 inline for ([_]bool{false, true}) |b1| {
636 inline for ([_]bool{false, true}) |b2| {
637 inline for ([_]bool{false, true}) |b3| {
638 inline for ([_]bool{false, true}) |b4| {
639 testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest();
640 }
641 }
642 }
643 }
644}
645
646fn testAsyncAwaitTypicalUsage(
647 comptime simulate_fail_download: bool,
648 comptime simulate_fail_file: bool,
649 comptime suspend_download: bool,
650 comptime suspend_file: bool) type
651{
652 return struct {
653 fn doTheTest() void {
654 _ = async amainWrap();
655 if (suspend_file) {
656 resume global_file_frame;
657 }
658 if (suspend_download) {
659 resume global_download_frame;
660 }
661 }
662 fn amainWrap() void {
663 if (amain()) |_| {
664 expect(!simulate_fail_download);
665 expect(!simulate_fail_file);
666 } else |e| switch (e) {
667 error.NoResponse => expect(simulate_fail_download),
668 error.FileNotFound => expect(simulate_fail_file),
669 else => @panic("test failure"),
670 }
671 }
672
673 fn amain() !void {
674 const allocator = std.heap.direct_allocator; // TODO once we have the debug allocator, use that, so that this can detect leaks
675 var download_frame = async fetchUrl(allocator, "https://example.com/");
676 var download_awaited = false;
677 errdefer if (!download_awaited) {
678 if (await download_frame) |x| allocator.free(x) else |_| {}
679 };
680
681 var file_frame = async readFile(allocator, "something.txt");
682 var file_awaited = false;
683 errdefer if (!file_awaited) {
684 if (await file_frame) |x| allocator.free(x) else |_| {}
685 };
686
687 download_awaited = true;
688 const download_text = try await download_frame;
689 defer allocator.free(download_text);
690
691 file_awaited = true;
692 const file_text = try await file_frame;
693 defer allocator.free(file_text);
694
695 expect(std.mem.eql(u8, "expected download text", download_text));
696 expect(std.mem.eql(u8, "expected file text", file_text));
697 }
698
699 var global_download_frame: anyframe = undefined;
700 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {
701 const result = try std.mem.dupe(allocator, u8, "expected download text");
702 errdefer allocator.free(result);
703 if (suspend_download) {
704 suspend {
705 global_download_frame = @frame();
706 }
707 }
708 if (simulate_fail_download) return error.NoResponse;
709 return result;
710 }
711
712 var global_file_frame: anyframe = undefined;
713 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {
714 const result = try std.mem.dupe(allocator, u8, "expected file text");
715 errdefer allocator.free(result);
716 if (suspend_file) {
717 suspend {
718 global_file_frame = @frame();
719 }
720 }
721 if (simulate_fail_file) return error.FileNotFound;
722 return result;
723 }
724 };
725}
726
727test "alignment of local variables in async functions" {
728 const S = struct {
729 fn doTheTest() void {
730 var y: u8 = 123;
731 var x: u8 align(128) = 1;
732 expect(@ptrToInt(&x) % 128 == 0);
733 }
734 };
735 S.doTheTest();
736}
test/stage1/behavior/await_struct.zig created+44
......@@ -0,0 +1,44 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const Foo = struct {
6 x: i32,
7};
8
9var await_a_promise: anyframe = undefined;
10var await_final_result = Foo{ .x = 0 };
11
12test "coroutine await struct" {
13 await_seq('a');
14 const p = async await_amain();
15 await_seq('f');
16 resume await_a_promise;
17 await_seq('i');
18 expect(await_final_result.x == 1234);
19 expect(std.mem.eql(u8, await_points, "abcdefghi"));
20}
21async fn await_amain() void {
22 await_seq('b');
23 const p = async await_another();
24 await_seq('e');
25 await_final_result = await p;
26 await_seq('h');
27}
28async fn await_another() Foo {
29 await_seq('c');
30 suspend {
31 await_seq('d');
32 await_a_promise = @frame();
33 }
34 await_seq('g');
35 return Foo{ .x = 1234 };
36}
37
38var await_points = [_]u8{0} ** "abcdefghi".len;
39var await_seq_index: usize = 0;
40
41fn await_seq(c: u8) void {
42 await_points[await_seq_index] = c;
43 await_seq_index += 1;
44}
test/stage1/behavior/cancel.zig deleted-86
......@@ -1,86 +0,0 @@
1const std = @import("std");
2
3var defer_f1: bool = false;
4var defer_f2: bool = false;
5var defer_f3: bool = false;
6
7test "cancel forwards" {
8 const p = async<std.heap.direct_allocator> f1() catch unreachable;
9 cancel p;
10 std.testing.expect(defer_f1);
11 std.testing.expect(defer_f2);
12 std.testing.expect(defer_f3);
13}
14
15async fn f1() void {
16 defer {
17 defer_f1 = true;
18 }
19 await (async f2() catch unreachable);
20}
21
22async fn f2() void {
23 defer {
24 defer_f2 = true;
25 }
26 await (async f3() catch unreachable);
27}
28
29async fn f3() void {
30 defer {
31 defer_f3 = true;
32 }
33 suspend;
34}
35
36var defer_b1: bool = false;
37var defer_b2: bool = false;
38var defer_b3: bool = false;
39var defer_b4: bool = false;
40
41test "cancel backwards" {
42 const p = async<std.heap.direct_allocator> b1() catch unreachable;
43 cancel p;
44 std.testing.expect(defer_b1);
45 std.testing.expect(defer_b2);
46 std.testing.expect(defer_b3);
47 std.testing.expect(defer_b4);
48}
49
50async fn b1() void {
51 defer {
52 defer_b1 = true;
53 }
54 await (async b2() catch unreachable);
55}
56
57var b4_handle: promise = undefined;
58
59async fn b2() void {
60 const b3_handle = async b3() catch unreachable;
61 resume b4_handle;
62 cancel b4_handle;
63 defer {
64 defer_b2 = true;
65 }
66 const value = await b3_handle;
67 @panic("unreachable");
68}
69
70async fn b3() i32 {
71 defer {
72 defer_b3 = true;
73 }
74 await (async b4() catch unreachable);
75 return 1234;
76}
77
78async fn b4() void {
79 defer {
80 defer_b4 = true;
81 }
82 suspend {
83 b4_handle = @handle();
84 }
85 suspend;
86}
test/stage1/behavior/coroutine_await_struct.zig deleted-44
......@@ -1,44 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const Foo = struct {
6 x: i32,
7};
8
9var await_a_promise: promise = undefined;
10var await_final_result = Foo{ .x = 0 };
11
12test "coroutine await struct" {
13 await_seq('a');
14 const p = async<std.heap.direct_allocator> await_amain() catch unreachable;
15 await_seq('f');
16 resume await_a_promise;
17 await_seq('i');
18 expect(await_final_result.x == 1234);
19 expect(std.mem.eql(u8, await_points, "abcdefghi"));
20}
21async fn await_amain() void {
22 await_seq('b');
23 const p = async await_another() catch unreachable;
24 await_seq('e');
25 await_final_result = await p;
26 await_seq('h');
27}
28async fn await_another() Foo {
29 await_seq('c');
30 suspend {
31 await_seq('d');
32 await_a_promise = @handle();
33 }
34 await_seq('g');
35 return Foo{ .x = 1234 };
36}
37
38var await_points = [_]u8{0} ** "abcdefghi".len;
39var await_seq_index: usize = 0;
40
41fn await_seq(c: u8) void {
42 await_points[await_seq_index] = c;
43 await_seq_index += 1;
44}
test/stage1/behavior/coroutines.zig deleted-236
......@@ -1,236 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const allocator = std.heap.direct_allocator;
5
6var x: i32 = 1;
7
8test "create a coroutine and cancel it" {
9 const p = try async<allocator> simpleAsyncFn();
10 comptime expect(@typeOf(p) == promise->void);
11 cancel p;
12 expect(x == 2);
13}
14async fn simpleAsyncFn() void {
15 x += 1;
16 suspend;
17 x += 1;
18}
19
20test "coroutine suspend, resume, cancel" {
21 seq('a');
22 const p = try async<allocator> testAsyncSeq();
23 seq('c');
24 resume p;
25 seq('f');
26 cancel p;
27 seq('g');
28
29 expect(std.mem.eql(u8, points, "abcdefg"));
30}
31async fn testAsyncSeq() void {
32 defer seq('e');
33
34 seq('b');
35 suspend;
36 seq('d');
37}
38var points = [_]u8{0} ** "abcdefg".len;
39var index: usize = 0;
40
41fn seq(c: u8) void {
42 points[index] = c;
43 index += 1;
44}
45
46test "coroutine suspend with block" {
47 const p = try async<allocator> testSuspendBlock();
48 std.testing.expect(!result);
49 resume a_promise;
50 std.testing.expect(result);
51 cancel p;
52}
53
54var a_promise: promise = undefined;
55var result = false;
56async fn testSuspendBlock() void {
57 suspend {
58 comptime expect(@typeOf(@handle()) == promise->void);
59 a_promise = @handle();
60 }
61
62 //Test to make sure that @handle() works as advertised (issue #1296)
63 //var our_handle: promise = @handle();
64 expect(a_promise == @handle());
65
66 result = true;
67}
68
69var await_a_promise: promise = undefined;
70var await_final_result: i32 = 0;
71
72test "coroutine await" {
73 await_seq('a');
74 const p = async<allocator> await_amain() catch unreachable;
75 await_seq('f');
76 resume await_a_promise;
77 await_seq('i');
78 expect(await_final_result == 1234);
79 expect(std.mem.eql(u8, await_points, "abcdefghi"));
80}
81async fn await_amain() void {
82 await_seq('b');
83 const p = async await_another() catch unreachable;
84 await_seq('e');
85 await_final_result = await p;
86 await_seq('h');
87}
88async fn await_another() i32 {
89 await_seq('c');
90 suspend {
91 await_seq('d');
92 await_a_promise = @handle();
93 }
94 await_seq('g');
95 return 1234;
96}
97
98var await_points = [_]u8{0} ** "abcdefghi".len;
99var await_seq_index: usize = 0;
100
101fn await_seq(c: u8) void {
102 await_points[await_seq_index] = c;
103 await_seq_index += 1;
104}
105
106var early_final_result: i32 = 0;
107
108test "coroutine await early return" {
109 early_seq('a');
110 const p = async<allocator> early_amain() catch @panic("out of memory");
111 early_seq('f');
112 expect(early_final_result == 1234);
113 expect(std.mem.eql(u8, early_points, "abcdef"));
114}
115async fn early_amain() void {
116 early_seq('b');
117 const p = async early_another() catch @panic("out of memory");
118 early_seq('d');
119 early_final_result = await p;
120 early_seq('e');
121}
122async fn early_another() i32 {
123 early_seq('c');
124 return 1234;
125}
126
127var early_points = [_]u8{0} ** "abcdef".len;
128var early_seq_index: usize = 0;
129
130fn early_seq(c: u8) void {
131 early_points[early_seq_index] = c;
132 early_seq_index += 1;
133}
134
135test "coro allocation failure" {
136 var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0);
137 if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) {
138 @panic("expected allocation failure");
139 } else |err| switch (err) {
140 error.OutOfMemory => {},
141 }
142}
143async fn asyncFuncThatNeverGetsRun() void {
144 @panic("coro frame allocation should fail");
145}
146
147test "async function with dot syntax" {
148 const S = struct {
149 var y: i32 = 1;
150 async fn foo() void {
151 y += 1;
152 suspend;
153 }
154 };
155 const p = try async<allocator> S.foo();
156 cancel p;
157 expect(S.y == 2);
158}
159
160test "async fn pointer in a struct field" {
161 var data: i32 = 1;
162 const Foo = struct {
163 bar: async<*std.mem.Allocator> fn (*i32) void,
164 };
165 var foo = Foo{ .bar = simpleAsyncFn2 };
166 const p = (async<allocator> foo.bar(&data)) catch unreachable;
167 expect(data == 2);
168 cancel p;
169 expect(data == 4);
170}
171async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
172 defer y.* += 2;
173 y.* += 1;
174 suspend;
175}
176
177test "async fn with inferred error set" {
178 const p = (async<allocator> failing()) catch unreachable;
179 resume p;
180 cancel p;
181}
182
183async fn failing() !void {
184 suspend;
185 return error.Fail;
186}
187
188test "error return trace across suspend points - early return" {
189 const p = nonFailing();
190 resume p;
191 const p2 = try async<allocator> printTrace(p);
192 cancel p2;
193}
194
195test "error return trace across suspend points - async return" {
196 const p = nonFailing();
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 resume p;
199 cancel p2;
200}
201
202fn nonFailing() (promise->anyerror!void) {
203 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
204}
205async fn suspendThenFail() anyerror!void {
206 suspend;
207 return error.Fail;
208}
209async fn printTrace(p: promise->(anyerror!void)) void {
210 (await p) catch |e| {
211 std.testing.expect(e == error.Fail);
212 if (@errorReturnTrace()) |trace| {
213 expect(trace.index == 1);
214 } else switch (builtin.mode) {
215 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
216 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
217 }
218 };
219}
220
221test "break from suspend" {
222 var buf: [500]u8 = undefined;
223 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
224 var my_result: i32 = 1;
225 const p = try async<a> testBreakFromSuspend(&my_result);
226 cancel p;
227 std.testing.expect(my_result == 2);
228}
229async fn testBreakFromSuspend(my_result: *i32) void {
230 suspend {
231 resume @handle();
232 }
233 my_result.* += 1;
234 suspend;
235 my_result.* += 1;
236}
test/stage1/behavior/type_info.zig+20-17
......@@ -116,21 +116,6 @@ fn testOptional() void {
116116 expect(null_info.Optional.child == void);
117117}
118118
119test "type info: promise info" {
120 testPromise();
121 comptime testPromise();
122}
123
124fn testPromise() void {
125 const null_promise_info = @typeInfo(promise);
126 expect(TypeId(null_promise_info) == TypeId.Promise);
127 expect(null_promise_info.Promise.child == null);
128
129 const promise_info = @typeInfo(promise->usize);
130 expect(TypeId(promise_info) == TypeId.Promise);
131 expect(promise_info.Promise.child.? == usize);
132}
133
134119test "type info: error set, error union info" {
135120 testErrorSet();
136121 comptime testErrorSet();
......@@ -192,7 +177,7 @@ fn testUnion() void {
192177 expect(TypeId(typeinfo_info) == TypeId.Union);
193178 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
194179 expect(typeinfo_info.Union.tag_type.? == TypeId);
195 expect(typeinfo_info.Union.fields.len == 25);
180 expect(typeinfo_info.Union.fields.len == 26);
196181 expect(typeinfo_info.Union.fields[4].enum_field != null);
197182 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
198183 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
......@@ -265,7 +250,6 @@ fn testFunction() void {
265250 expect(fn_info.Fn.args.len == 2);
266251 expect(fn_info.Fn.is_var_args);
267252 expect(fn_info.Fn.return_type == null);
268 expect(fn_info.Fn.async_allocator_type == null);
269253
270254 const test_instance: TestStruct = undefined;
271255 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
......@@ -296,6 +280,25 @@ fn testVector() void {
296280 expect(vec_info.Vector.child == i32);
297281}
298282
283test "type info: anyframe and anyframe->T" {
284 testAnyFrame();
285 comptime testAnyFrame();
286}
287
288fn testAnyFrame() void {
289 {
290 const anyframe_info = @typeInfo(anyframe->i32);
291 expect(TypeId(anyframe_info) == .AnyFrame);
292 expect(anyframe_info.AnyFrame.child.? == i32);
293 }
294
295 {
296 const anyframe_info = @typeInfo(anyframe);
297 expect(TypeId(anyframe_info) == .AnyFrame);
298 expect(anyframe_info.AnyFrame.child == null);
299 }
300}
301
299302test "type info: optional field unwrapping" {
300303 const Struct = struct {
301304 cdOffset: u32,