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
signature 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")...@@ -426,7 +426,6 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
426set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")426set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")
427427
428set(ZIG_SOURCES428set(ZIG_SOURCES
429 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
430 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"429 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
431 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"430 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
432 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"431 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
...@@ -438,6 +437,7 @@ set(ZIG_SOURCES...@@ -438,6 +437,7 @@ set(ZIG_SOURCES
438 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"437 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"
439 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"438 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
440 "${CMAKE_SOURCE_DIR}/src/error.cpp"439 "${CMAKE_SOURCE_DIR}/src/error.cpp"
440 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
441 "${CMAKE_SOURCE_DIR}/src/ir.cpp"441 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
442 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"442 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
443 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"443 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
build.zig+3-1
...@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {...@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {
375 artifact.bundle_compiler_rt = true;375 artifact.bundle_compiler_rt = true;
376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
377 artifact.linkSystemLibrary("c");377 artifact.linkSystemLibrary("c");
378 artifact.linkSystemLibrary("ntdll");378 if (builtin.os == .windows) {
379 artifact.linkSystemLibrary("ntdll");
380 }
379 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");381 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
380 libuserland_step.dependOn(&artifact.step);382 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...@@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
750 .Keyword_async,750 .Keyword_async,
751 .Keyword_await,751 .Keyword_await,
752 .Keyword_break,752 .Keyword_break,
753 .Keyword_cancel,
754 .Keyword_catch,753 .Keyword_catch,
755 .Keyword_comptime,754 .Keyword_comptime,
756 .Keyword_const,755 .Keyword_const,
...@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
770 .Keyword_or,769 .Keyword_or,
771 .Keyword_orelse,770 .Keyword_orelse,
772 .Keyword_packed,771 .Keyword_packed,
773 .Keyword_promise,772 .Keyword_anyframe,
774 .Keyword_pub,773 .Keyword_pub,
775 .Keyword_resume,774 .Keyword_resume,
776 .Keyword_return,775 .Keyword_return,
doc/langref.html.in+332-170
...@@ -5968,55 +5968,27 @@ test "global assembly" {...@@ -5968,55 +5968,27 @@ test "global assembly" {
5968 <p>TODO: @atomic rmw</p>5968 <p>TODO: @atomic rmw</p>
5969 <p>TODO: builtin atomic memory ordering enum</p>5969 <p>TODO: builtin atomic memory ordering enum</p>
5970 {#header_close#}5970 {#header_close#}
5971 {#header_open|Coroutines#}5971 {#header_open|Async Functions#}
5972 <p>5972 <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.
5974 </p>5976 </p>
5975 <p>5977 <p>
5976 When you call a function, it creates a stack frame,5978 An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
5977 and then the function runs until it reaches a return5979 followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
5978 statement, and then the stack frame is destroyed.5980 provided explicitly by the caller, and it can be suspended and resumed any number of times.
5979 At the callsite, the next line of code does not run
5980 until the function returns.
5981 </p>5981 </p>
5982 <p>5982 <p>
5983 A coroutine is like a function, but it can be suspended5983 Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
5984 and resumed any number of times, and then it must be5984 a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
5985 explicitly destroyed. When a coroutine suspends, it5985 function call of an async function is a suspend point.
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#}:
6016 </p>5986 </p>
5987 {#header_open|Suspend and Resume#}
6017 <p>5988 <p>
6018 Async functions start executing when created, so in the following example, the entire5989 At any point, a function may suspend itself. This causes control flow to
6019 async function completes before it is canceled:5990 return to the callsite (in the case of the first suspension),
5991 or resumer (in the case of subsequent suspensions).
6020 </p>5992 </p>
6021 {#code_begin|test#}5993 {#code_begin|test#}
6022const std = @import("std");5994const std = @import("std");
...@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;...@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;
60245996
6025var x: i32 = 1;5997var x: i32 = 1;
60265998
6027test "create a coroutine and cancel it" {5999test "suspend with no resume" {
6028 const p = try async<std.debug.global_allocator> simpleAsyncFn();6000 var frame = async func();
6029 comptime assert(@typeOf(p) == promise->void);
6030 cancel p;
6031 assert(x == 2);6001 assert(x == 2);
6032}6002}
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"));6004fn func() void {
6058}6005 x += 1;
6059async fn testAsyncSeq() void {
6060 defer seq('e');
6061
6062 seq('b');
6063 suspend;6006 suspend;
6064 seq('d');6007 // This line is never reached because the suspend has no matching resume.
6065}6008 x += 1;
6066var points = [_]u8{0} ** "abcdefg".len;
6067var index: usize = 0;
6068
6069fn seq(c: u8) void {
6070 points[index] = c;
6071 index += 1;
6072}6009}
6073 {#code_end#}6010 {#code_end#}
6074 <p>6011 <p>
6075 When an async function suspends itself, it must be sure that it will be6012 In the same way that each allocation should have a corresponding free,
6076 resumed or canceled somehow, for example by registering its promise handle6013 Each {#syntax#}suspend{#endsyntax#} should have a corresponding {#syntax#}resume{#endsyntax#}.
6077 in an event loop. Use a suspend capture block to gain access to the6014 A <strong>suspend block</strong> allows a function to put a pointer to its own
6078 promise: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.
6079 </p>6018 </p>
6080 {#code_begin|test#}6019 {#code_begin|test#}
6081const std = @import("std");6020const std = @import("std");
6082const assert = std.debug.assert;6021const assert = std.debug.assert;
60836022
6084test "coroutine suspend with block" {6023var the_frame: anyframe = undefined;
6085 const p = try async<std.debug.global_allocator> testSuspendBlock();6024var result = false;
6086 std.debug.assert(!result);6025
6087 resume a_promise;6026test "async function suspend with block" {
6088 std.debug.assert(result);6027 _ = async testSuspendBlock();
6089 cancel p;6028 assert(!result);
6029 resume the_frame;
6030 assert(result);
6090}6031}
60916032
6092var a_promise: promise = undefined;6033fn testSuspendBlock() void {
6093var result = false;
6094async fn testSuspendBlock() void {
6095 suspend {6034 suspend {
6096 comptime assert(@typeOf(@handle()) == promise->void);6035 comptime assert(@typeOf(@frame()) == *@Frame(testSuspendBlock));
6097 a_promise = @handle();6036 the_frame = @frame();
6098 }6037 }
6099 result = true;6038 result = true;
6100}6039}
6101 {#code_end#}6040 {#code_end#}
6102 <p>6041 <p>
6103 Every suspend point in an async function represents a point at which the coroutine6042 {#syntax#}suspend{#endsyntax#} causes a function to be {#syntax#}async{#endsyntax#}.
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.
6109 </p>6043 </p>
6044
6110 {#header_open|Resuming from Suspend Blocks#}6045 {#header_open|Resuming from Suspend Blocks#}
6111 <p>6046 <p>
6112 Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered6047 Upon entering a {#syntax#}suspend{#endsyntax#} block, the async function is already considered
6113 suspended, and can be resumed. For example, if you started another kernel thread,6048 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 the6049 and had that thread call {#syntax#}resume{#endsyntax#} on the frame pointer provided by the
6115 {#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend6050 {#link|@frame#}, the new thread would begin executing after the suspend
6116 block, while the old thread continued executing the suspend block.6051 block, while the old thread continued executing the suspend block.
6117 </p>6052 </p>
6118 <p>6053 <p>
6119 However, the coroutine can be directly resumed from the suspend block, in which case it6054 However, the async function can be directly resumed from the suspend block, in which case it
6120 never returns to its resumer and continues executing.6055 never returns to its resumer and continues executing.
6121 </p>6056 </p>
6122 {#code_begin|test#}6057 {#code_begin|test#}
...@@ -6124,16 +6059,13 @@ const std = @import("std");...@@ -6124,16 +6059,13 @@ const std = @import("std");
6124const assert = std.debug.assert;6059const assert = std.debug.assert;
61256060
6126test "resume from suspend" {6061test "resume from suspend" {
6127 var buf: [500]u8 = undefined;
6128 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
6129 var my_result: i32 = 1;6062 var my_result: i32 = 1;
6130 const p = try async<a> testResumeFromSuspend(&my_result);6063 _ = async testResumeFromSuspend(&my_result);
6131 cancel p;
6132 std.debug.assert(my_result == 2);6064 std.debug.assert(my_result == 2);
6133}6065}
6134async fn testResumeFromSuspend(my_result: *i32) void {6066fn testResumeFromSuspend(my_result: *i32) void {
6135 suspend {6067 suspend {
6136 resume @handle();6068 resume @frame();
6137 }6069 }
6138 my_result.* += 1;6070 my_result.* += 1;
6139 suspend;6071 suspend;
...@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {...@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {
6141}6073}
6142 {#code_end#}6074 {#code_end#}
6143 <p>6075 <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.
6145 </p>6077 </p>
6146 {#header_close#}6078 {#header_close#}
6147 {#header_close#}6079 {#header_close#}
6148 {#header_open|Await#}6080
6081 {#header_open|Async and Await#}
6149 <p>6082 <p>
6150 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's6083 In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
6151 {#syntax#}return{#endsyntax#} statement.6084 {#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}.
6152 </p>6085 </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#}
6153 <p>6115 <p>
6154 {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes6116 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6155 as an operand a promise handle.6117 {#syntax#}return{#endsyntax#} statement.
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.
6163 </p>6118 </p>
6164 <p>6119 <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#}.
6166 </p>6122 </p>
6167 <p>6123 <p>
6168 {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},6124 There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
6169 a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.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.
6170 </p>6129 </p>
6171 {#code_begin|test#}6130 {#code_begin|test#}
6172const std = @import("std");6131const std = @import("std");
6173const assert = std.debug.assert;6132const assert = std.debug.assert;
61746133
6175var a_promise: promise = undefined;6134var the_frame: anyframe = undefined;
6176var final_result: i32 = 0;6135var final_result: i32 = 0;
61776136
6178test "coroutine await" {6137test "async function await" {
6179 seq('a');6138 seq('a');
6180 const p = async<std.debug.global_allocator> amain() catch unreachable;6139 _ = async amain();
6181 seq('f');6140 seq('f');
6182 resume a_promise;6141 resume the_frame;
6183 seq('i');6142 seq('i');
6184 assert(final_result == 1234);6143 assert(final_result == 1234);
6185 assert(std.mem.eql(u8, seq_points, "abcdefghi"));6144 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
6186}6145}
6187async fn amain() void {6146fn amain() void {
6188 seq('b');6147 seq('b');
6189 const p = async another() catch unreachable;6148 var f = async another();
6190 seq('e');6149 seq('e');
6191 final_result = await p;6150 final_result = await f;
6192 seq('h');6151 seq('h');
6193}6152}
6194async fn another() i32 {6153fn another() i32 {
6195 seq('c');6154 seq('c');
6196 suspend {6155 suspend {
6197 seq('d');6156 seq('d');
6198 a_promise = @handle();6157 the_frame = @frame();
6199 }6158 }
6200 seq('g');6159 seq('g');
6201 return 1234;6160 return 1234;
...@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {...@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {
6211 {#code_end#}6170 {#code_end#}
6212 <p>6171 <p>
6213 In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application6172 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 loop6173 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6215 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.6174 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
6216 </p>6175 </p>
6217 {#header_close#}6176 {#header_close#}
6218 {#header_open|Open Issues#}6177
6178 {#header_open|Async Function Example#}
6219 <p>6179 <p>
6220 There are a few issues with coroutines that are considered unresolved. Best be aware of them,6180 Putting all of this together, here is an example of typical
6221 as the situation is likely to change before 1.0.0: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.
6222 </p>6322 </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>
6239 {#header_close#}6323 {#header_close#}
62406324
6241 {#header_close#}6325 {#header_close#}
...@@ -6293,6 +6377,49 @@ comptime {...@@ -6293,6 +6377,49 @@ comptime {
6293 Note: This function is deprecated. Use {#link|@typeInfo#} instead.6377 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
6294 </p>6378 </p>
6295 {#header_close#}6379 {#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
6296 {#header_open|@atomicLoad#}6423 {#header_open|@atomicLoad#}
6297 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>6424 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
6298 <p>6425 <p>
...@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}...@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}
6883 {#see_also|@intToFloat#}7010 {#see_also|@intToFloat#}
6884 {#header_close#}7011 {#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
6886 {#header_open|@frameAddress#}7051 {#header_open|@frameAddress#}
6887 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>7052 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
6888 <p>7053 <p>
...@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}...@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}
6898 </p>7063 </p>
6899 {#header_close#}7064 {#header_close#}
69007065
6901 {#header_open|@handle#}7066 {#header_open|@frameSize#}
6902 <pre>{#syntax#}@handle(){#endsyntax#}</pre>7067 <pre>{#syntax#}@frameSize() usize{#endsyntax#}</pre>
6903 <p>7068 <p>
6904 This function returns a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}7069 This is the same as {#syntax#}@sizeOf(@Frame(func)){#endsyntax#}, where {#syntax#}func{#endsyntax#}
6905 is the return type of the async function in scope.7070 may be runtime-known.
6906 </p>7071 </p>
6907 <p>7072 <p>
6908 This function is only valid within an async function scope.7073 This function is typically used in conjunction with {#link|@asyncCall#}.
6909 </p>7074 </p>
6910 {#header_close#}7075 {#header_close#}
69117076
...@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {...@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {
8045 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:8210 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
8046 <ul>8211 <ul>
8047 <li>All {#link|Thread Local Variables#} are treated as {#link|Global Variables#}.</li>8212 <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.8213 <li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
8049 TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
8050 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}8214 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
8051 and therefore various userland APIs which read this variable become more efficient.8215 and therefore various userland APIs which read this variable become more efficient.
8052 For example {#syntax#}std.Mutex{#endsyntax#} becomes8216 For example {#syntax#}std.Mutex{#endsyntax#} becomes
...@@ -9793,7 +9957,6 @@ PrimaryExpr...@@ -9793,7 +9957,6 @@ PrimaryExpr
9793 &lt;- AsmExpr9957 &lt;- AsmExpr
9794 / IfExpr9958 / IfExpr
9795 / KEYWORD_break BreakLabel? Expr?9959 / KEYWORD_break BreakLabel? Expr?
9796 / KEYWORD_cancel Expr
9797 / KEYWORD_comptime Expr9960 / KEYWORD_comptime Expr
9798 / KEYWORD_continue BreakLabel?9961 / KEYWORD_continue BreakLabel?
9799 / KEYWORD_resume Expr9962 / KEYWORD_resume Expr
...@@ -10149,7 +10312,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word...@@ -10149,7 +10312,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word
10149KEYWORD_async &lt;- 'async' end_of_word10312KEYWORD_async &lt;- 'async' end_of_word
10150KEYWORD_await &lt;- 'await' end_of_word10313KEYWORD_await &lt;- 'await' end_of_word
10151KEYWORD_break &lt;- 'break' end_of_word10314KEYWORD_break &lt;- 'break' end_of_word
10152KEYWORD_cancel &lt;- 'cancel' end_of_word
10153KEYWORD_catch &lt;- 'catch' end_of_word10315KEYWORD_catch &lt;- 'catch' end_of_word
10154KEYWORD_comptime &lt;- 'comptime' end_of_word10316KEYWORD_comptime &lt;- 'comptime' end_of_word
10155KEYWORD_const &lt;- 'const' end_of_word10317KEYWORD_const &lt;- 'const' end_of_word
...@@ -10194,7 +10356,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word...@@ -10194,7 +10356,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word
10194KEYWORD_while &lt;- 'while' end_of_word10356KEYWORD_while &lt;- 'while' end_of_word
1019510357
10196keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm10358keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm
10197 / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel10359 / KEYWORD_async / KEYWORD_await / KEYWORD_break
10198 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue10360 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
10199 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer10361 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
10200 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false10362 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
src-self-hosted/ir.zig-14
...@@ -1904,20 +1904,6 @@ pub const Builder = struct {...@@ -1904,20 +1904,6 @@ pub const Builder = struct {
1904 }1904 }
1905 return error.Unimplemented;1905 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
1921 }1907 }
19221908
1923 const Ident = union(enum) {1909 const Ident = union(enum) {
src-self-hosted/link.zig+1-1
...@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {...@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
627627
628fn addFnObjects(ctx: *Context) !void {628fn addFnObjects(ctx: *Context) !void {
629 // at this point it's guaranteed nobody else has this lock, so we circumvent it629 // at this point it's guaranteed nobody else has this lock, so we circumvent it
630 // and avoid having to be a coroutine630 // and avoid having to be an async function
631 const fn_link_set = &ctx.comp.fn_link_set.private_data;631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
632632
633 var it = fn_link_set.first;633 var it = fn_link_set.first;
src-self-hosted/main.zig+9-12
...@@ -52,7 +52,7 @@ const Command = struct {...@@ -52,7 +52,7 @@ const Command = struct {
5252
53pub fn main() !void {53pub fn main() !void {
54 // This allocator needs to be thread-safe because we use it for the event.Loop54 // 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.
56 // libc allocator is guaranteed to have this property.56 // libc allocator is guaranteed to have this property.
57 const allocator = std.heap.c_allocator;57 const allocator = std.heap.c_allocator;
5858
...@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
466 comp.link_objects = link_objects;466 comp.link_objects = link_objects;
467467
468 comp.start();468 comp.start();
469 const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);469 // TODO const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
470 defer cancel process_build_events_handle;
471 loop.run();470 loop.run();
472}471}
473472
...@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
578 var zig_compiler = try ZigCompiler.init(&loop);577 var zig_compiler = try ZigCompiler.init(&loop);
579 defer zig_compiler.deinit();578 defer zig_compiler.deinit();
580579
581 const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);580 // TODO const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
582 defer cancel handle;
583581
584 loop.run();582 loop.run();
585}583}
...@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
663 defer loop.deinit();661 defer loop.deinit();
664662
665 var result: FmtError!void = undefined;663 var result: FmtError!void = undefined;
666 const main_handle = try async<allocator> asyncFmtMainChecked(664 // TODO const main_handle = try async<allocator> asyncFmtMainChecked(
667 &result,665 // TODO &result,
668 &loop,666 // TODO &loop,
669 &flags,667 // TODO &flags,
670 color,668 // TODO color,
671 );669 // TODO );
672 defer cancel main_handle;
673 loop.run();670 loop.run();
674 return result;671 return result;
675}672}
src-self-hosted/stage1.zig+2-1
...@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {...@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
142 return Error.None;142 return Error.None;
143}143}
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.
146export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {147export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
147 if (std.debug.runtime_safety) {148 if (std.debug.runtime_safety) {
148 fmtMain(argc, argv) catch unreachable;149 fmtMain(argc, argv) catch unreachable;
src/all_types.hpp+161-216
...@@ -35,6 +35,7 @@ struct ConstExprValue;...@@ -35,6 +35,7 @@ struct ConstExprValue;
35struct IrInstruction;35struct IrInstruction;
36struct IrInstructionCast;36struct IrInstructionCast;
37struct IrInstructionAllocaGen;37struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;
38struct IrBasicBlock;39struct IrBasicBlock;
39struct ScopeDecls;40struct ScopeDecls;
40struct ZigWindowsSDK;41struct ZigWindowsSDK;
...@@ -70,20 +71,10 @@ struct IrExecutable {...@@ -70,20 +71,10 @@ struct IrExecutable {
70 Scope *begin_scope;71 Scope *begin_scope;
71 ZigList<Tld *> tld_list;72 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
84 bool invalid;74 bool invalid;
85 bool is_inline;75 bool is_inline;
86 bool is_generic_instantiation;76 bool is_generic_instantiation;
77 bool need_err_code_spill;
87};78};
8879
89enum OutType {80enum OutType {
...@@ -485,11 +476,10 @@ enum NodeType {...@@ -485,11 +476,10 @@ enum NodeType {
485 NodeTypeIfErrorExpr,476 NodeTypeIfErrorExpr,
486 NodeTypeIfOptional,477 NodeTypeIfOptional,
487 NodeTypeErrorSetDecl,478 NodeTypeErrorSetDecl,
488 NodeTypeCancel,
489 NodeTypeResume,479 NodeTypeResume,
490 NodeTypeAwaitExpr,480 NodeTypeAwaitExpr,
491 NodeTypeSuspend,481 NodeTypeSuspend,
492 NodeTypePromiseType,482 NodeTypeAnyFrameType,
493 NodeTypeEnumLiteral,483 NodeTypeEnumLiteral,
494};484};
495485
...@@ -522,7 +512,6 @@ struct AstNodeFnProto {...@@ -522,7 +512,6 @@ struct AstNodeFnProto {
522 AstNode *section_expr;512 AstNode *section_expr;
523513
524 bool auto_err_set;514 bool auto_err_set;
525 AstNode *async_allocator_type;
526};515};
527516
528struct AstNodeFnDef {517struct AstNodeFnDef {
...@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {...@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {
657 bool is_builtin;646 bool is_builtin;
658 bool is_async;647 bool is_async;
659 bool seen; // used by @compileLog648 bool seen; // used by @compileLog
660 AstNode *async_allocator;
661};649};
662650
663struct AstNodeArrayAccessExpr {651struct AstNodeArrayAccessExpr {
...@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {...@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {
922 AstNode *expr; // may be null910 AstNode *expr; // may be null
923};911};
924912
925struct AstNodeCancelExpr {
926 AstNode *expr;
927};
928
929struct AstNodeResumeExpr {913struct AstNodeResumeExpr {
930 AstNode *expr;914 AstNode *expr;
931};915};
...@@ -949,7 +933,7 @@ struct AstNodeSuspend {...@@ -949,7 +933,7 @@ struct AstNodeSuspend {
949 AstNode *block;933 AstNode *block;
950};934};
951935
952struct AstNodePromiseType {936struct AstNodeAnyFrameType {
953 AstNode *payload_type; // can be NULL937 AstNode *payload_type; // can be NULL
954};938};
955939
...@@ -1014,13 +998,16 @@ struct AstNode {...@@ -1014,13 +998,16 @@ struct AstNode {
1014 AstNodeInferredArrayType inferred_array_type;998 AstNodeInferredArrayType inferred_array_type;
1015 AstNodeErrorType error_type;999 AstNodeErrorType error_type;
1016 AstNodeErrorSetDecl err_set_decl;1000 AstNodeErrorSetDecl err_set_decl;
1017 AstNodeCancelExpr cancel_expr;
1018 AstNodeResumeExpr resume_expr;1001 AstNodeResumeExpr resume_expr;
1019 AstNodeAwaitExpr await_expr;1002 AstNodeAwaitExpr await_expr;
1020 AstNodeSuspend suspend;1003 AstNodeSuspend suspend;
1021 AstNodePromiseType promise_type;1004 AstNodeAnyFrameType anyframe_type;
1022 AstNodeEnumLiteral enum_literal;1005 AstNodeEnumLiteral enum_literal;
1023 } data;1006 } data;
1007
1008 // This is a function for use in the debugger to print
1009 // the source location.
1010 void src();
1024};1011};
10251012
1026// this struct is allocated with allocate_nonzero1013// this struct is allocated with allocate_nonzero
...@@ -1047,7 +1034,6 @@ struct FnTypeId {...@@ -1047,7 +1034,6 @@ struct FnTypeId {
1047 bool is_var_args;1034 bool is_var_args;
1048 CallingConvention cc;1035 CallingConvention cc;
1049 uint32_t alignment;1036 uint32_t alignment;
1050 ZigType *async_allocator_type;
1051};1037};
10521038
1053uint32_t fn_type_id_hash(FnTypeId*);1039uint32_t fn_type_id_hash(FnTypeId*);
...@@ -1095,6 +1081,7 @@ struct TypeStructField {...@@ -1095,6 +1081,7 @@ struct TypeStructField {
1095 ConstExprValue *init_val; // null and then memoized1081 ConstExprValue *init_val; // null and then memoized
1096 uint32_t bit_offset_in_host; // offset from the memory at gen_index1082 uint32_t bit_offset_in_host; // offset from the memory at gen_index
1097 uint32_t host_int_bytes; // size of host integer1083 uint32_t host_int_bytes; // size of host integer
1084 uint32_t align;
1098};1085};
10991086
1100enum ResolveStatus {1087enum ResolveStatus {
...@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {...@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {
1156struct ZigTypeErrorUnion {1143struct ZigTypeErrorUnion {
1157 ZigType *err_set_type;1144 ZigType *err_set_type;
1158 ZigType *payload_type;1145 ZigType *payload_type;
1146 size_t pad_bytes;
1147 LLVMTypeRef pad_llvm_type;
1159};1148};
11601149
1161struct ZigTypeErrorSet {1150struct ZigTypeErrorSet {
...@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {...@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {
1241 ZigType *fn_type;1230 ZigType *fn_type;
1242};1231};
12431232
1244struct ZigTypePromise {
1245 // null if `promise` instead of `promise->T`
1246 ZigType *result_type;
1247};
1248
1249struct ZigTypeVector {1233struct ZigTypeVector {
1250 // The type must be a pointer, integer, or float1234 // The type must be a pointer, integer, or float
1251 ZigType *elem_type;1235 ZigType *elem_type;
...@@ -1276,7 +1260,8 @@ enum ZigTypeId {...@@ -1276,7 +1260,8 @@ enum ZigTypeId {
1276 ZigTypeIdBoundFn,1260 ZigTypeIdBoundFn,
1277 ZigTypeIdArgTuple,1261 ZigTypeIdArgTuple,
1278 ZigTypeIdOpaque,1262 ZigTypeIdOpaque,
1279 ZigTypeIdPromise,1263 ZigTypeIdFnFrame,
1264 ZigTypeIdAnyFrame,
1280 ZigTypeIdVector,1265 ZigTypeIdVector,
1281 ZigTypeIdEnumLiteral,1266 ZigTypeIdEnumLiteral,
1282};1267};
...@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {...@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {
1291 Buf *bare_name;1276 Buf *bare_name;
1292};1277};
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
1294struct ZigType {1288struct ZigType {
1295 ZigTypeId id;1289 ZigTypeId id;
1296 Buf name;1290 Buf name;
...@@ -1314,16 +1308,16 @@ struct ZigType {...@@ -1314,16 +1308,16 @@ struct ZigType {
1314 ZigTypeUnion unionation;1308 ZigTypeUnion unionation;
1315 ZigTypeFn fn;1309 ZigTypeFn fn;
1316 ZigTypeBoundFn bound_fn;1310 ZigTypeBoundFn bound_fn;
1317 ZigTypePromise promise;
1318 ZigTypeVector vector;1311 ZigTypeVector vector;
1319 ZigTypeOpaque opaque;1312 ZigTypeOpaque opaque;
1313 ZigTypeFnFrame frame;
1314 ZigTypeAnyFrame any_frame;
1320 } data;1315 } data;
13211316
1322 // use these fields to make sure we don't duplicate type table entries for the same type1317 // use these fields to make sure we don't duplicate type table entries for the same type
1323 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]1318 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]
1324 ZigType *optional_parent;1319 ZigType *optional_parent;
1325 ZigType *promise_parent;1320 ZigType *any_frame_parent;
1326 ZigType *promise_frame_parent;
1327 // If we generate a constant name value for this type, we memoize it here.1321 // If we generate a constant name value for this type, we memoize it here.
1328 // The type of this is array1322 // The type of this is array
1329 ConstExprValue *cached_const_name_val;1323 ConstExprValue *cached_const_name_val;
...@@ -1359,7 +1353,6 @@ struct GlobalExport {...@@ -1359,7 +1353,6 @@ struct GlobalExport {
1359};1353};
13601354
1361struct ZigFn {1355struct ZigFn {
1362 CodeGen *codegen;
1363 LLVMValueRef llvm_value;1356 LLVMValueRef llvm_value;
1364 const char *llvm_name;1357 const char *llvm_name;
1365 AstNode *proto_node;1358 AstNode *proto_node;
...@@ -1368,7 +1361,17 @@ struct ZigFn {...@@ -1368,7 +1361,17 @@ struct ZigFn {
1368 Scope *child_scope; // parent is scope for last parameter1361 Scope *child_scope; // parent is scope for last parameter
1369 ScopeBlock *def_scope; // parent is child_scope1362 ScopeBlock *def_scope; // parent is child_scope
1370 Buf symbol_name;1363 Buf symbol_name;
1371 ZigType *type_entry; // function type1364 // 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;
1372 // in the case of normal functions this is the implicit return type1375 // in the case of normal functions this is the implicit return type
1373 // in the case of async functions this is the implicit return type according to the1376 // in the case of async functions this is the implicit return type according to the
1374 // zig source code, not according to zig ir1377 // zig source code, not according to zig ir
...@@ -1379,6 +1382,7 @@ struct ZigFn {...@@ -1379,6 +1382,7 @@ struct ZigFn {
1379 size_t prealloc_backward_branch_quota;1382 size_t prealloc_backward_branch_quota;
1380 AstNode **param_source_nodes;1383 AstNode **param_source_nodes;
1381 Buf **param_names;1384 Buf **param_names;
1385 IrInstruction *err_code_spill;
13821386
1383 AstNode *fn_no_inline_set_node;1387 AstNode *fn_no_inline_set_node;
1384 AstNode *fn_static_eval_set_node;1388 AstNode *fn_static_eval_set_node;
...@@ -1390,8 +1394,11 @@ struct ZigFn {...@@ -1390,8 +1394,11 @@ struct ZigFn {
1390 AstNode *set_alignstack_node;1394 AstNode *set_alignstack_node;
13911395
1392 AstNode *set_cold_node;1396 AstNode *set_cold_node;
1397 const AstNode *inferred_async_node;
1398 ZigFn *inferred_async_fn;
13931399
1394 ZigList<GlobalExport> export_list;1400 ZigList<GlobalExport> export_list;
1401 ZigList<IrInstructionCallGen *> call_list;
13951402
1396 LLVMValueRef valgrind_client_request_array;1403 LLVMValueRef valgrind_client_request_array;
13971404
...@@ -1442,8 +1449,6 @@ enum BuiltinFnId {...@@ -1442,8 +1449,6 @@ enum BuiltinFnId {
1442 BuiltinFnIdErrName,1449 BuiltinFnIdErrName,
1443 BuiltinFnIdBreakpoint,1450 BuiltinFnIdBreakpoint,
1444 BuiltinFnIdReturnAddress,1451 BuiltinFnIdReturnAddress,
1445 BuiltinFnIdFrameAddress,
1446 BuiltinFnIdHandle,
1447 BuiltinFnIdEmbedFile,1452 BuiltinFnIdEmbedFile,
1448 BuiltinFnIdCmpxchgWeak,1453 BuiltinFnIdCmpxchgWeak,
1449 BuiltinFnIdCmpxchgStrong,1454 BuiltinFnIdCmpxchgStrong,
...@@ -1499,6 +1504,7 @@ enum BuiltinFnId {...@@ -1499,6 +1504,7 @@ enum BuiltinFnId {
1499 BuiltinFnIdInlineCall,1504 BuiltinFnIdInlineCall,
1500 BuiltinFnIdNoInlineCall,1505 BuiltinFnIdNoInlineCall,
1501 BuiltinFnIdNewStackCall,1506 BuiltinFnIdNewStackCall,
1507 BuiltinFnIdAsyncCall,
1502 BuiltinFnIdTypeId,1508 BuiltinFnIdTypeId,
1503 BuiltinFnIdShlExact,1509 BuiltinFnIdShlExact,
1504 BuiltinFnIdShrExact,1510 BuiltinFnIdShrExact,
...@@ -1514,6 +1520,10 @@ enum BuiltinFnId {...@@ -1514,6 +1520,10 @@ enum BuiltinFnId {
1514 BuiltinFnIdAtomicLoad,1520 BuiltinFnIdAtomicLoad,
1515 BuiltinFnIdHasDecl,1521 BuiltinFnIdHasDecl,
1516 BuiltinFnIdUnionInit,1522 BuiltinFnIdUnionInit,
1523 BuiltinFnIdFrameAddress,
1524 BuiltinFnIdFrameType,
1525 BuiltinFnIdFrameHandle,
1526 BuiltinFnIdFrameSize,
1517};1527};
15181528
1519struct BuiltinFnEntry {1529struct BuiltinFnEntry {
...@@ -1541,6 +1551,12 @@ enum PanicMsgId {...@@ -1541,6 +1551,12 @@ enum PanicMsgId {
1541 PanicMsgIdBadEnumValue,1551 PanicMsgIdBadEnumValue,
1542 PanicMsgIdFloatToInt,1552 PanicMsgIdFloatToInt,
1543 PanicMsgIdPtrCastNull,1553 PanicMsgIdPtrCastNull,
1554 PanicMsgIdBadResume,
1555 PanicMsgIdBadAwait,
1556 PanicMsgIdBadReturn,
1557 PanicMsgIdResumedAnAwaitingFn,
1558 PanicMsgIdFrameTooSmall,
1559 PanicMsgIdResumedFnPendingAwait,
15441560
1545 PanicMsgIdCount,1561 PanicMsgIdCount,
1546};1562};
...@@ -1701,7 +1717,13 @@ struct CodeGen {...@@ -1701,7 +1717,13 @@ struct CodeGen {
1701 LLVMTargetMachineRef target_machine;1717 LLVMTargetMachineRef target_machine;
1702 ZigLLVMDIFile *dummy_di_file;1718 ZigLLVMDIFile *dummy_di_file;
1703 LLVMValueRef cur_ret_ptr;1719 LLVMValueRef cur_ret_ptr;
1720 LLVMValueRef cur_frame_ptr;
1704 LLVMValueRef cur_fn_val;1721 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;
1705 LLVMValueRef cur_err_ret_trace_val_arg;1727 LLVMValueRef cur_err_ret_trace_val_arg;
1706 LLVMValueRef cur_err_ret_trace_val_stack;1728 LLVMValueRef cur_err_ret_trace_val_stack;
1707 LLVMValueRef memcpy_fn_val;1729 LLVMValueRef memcpy_fn_val;
...@@ -1709,28 +1731,16 @@ struct CodeGen {...@@ -1709,28 +1731,16 @@ struct CodeGen {
1709 LLVMValueRef trap_fn_val;1731 LLVMValueRef trap_fn_val;
1710 LLVMValueRef return_address_fn_val;1732 LLVMValueRef return_address_fn_val;
1711 LLVMValueRef frame_address_fn_val;1733 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;
1726 LLVMValueRef add_error_return_trace_addr_fn_val;1734 LLVMValueRef add_error_return_trace_addr_fn_val;
1727 LLVMValueRef stacksave_fn_val;1735 LLVMValueRef stacksave_fn_val;
1728 LLVMValueRef stackrestore_fn_val;1736 LLVMValueRef stackrestore_fn_val;
1729 LLVMValueRef write_register_fn_val;1737 LLVMValueRef write_register_fn_val;
1738 LLVMValueRef merge_err_ret_traces_fn_val;
1730 LLVMValueRef sp_md_node;1739 LLVMValueRef sp_md_node;
1731 LLVMValueRef err_name_table;1740 LLVMValueRef err_name_table;
1732 LLVMValueRef safety_crash_err_fn;1741 LLVMValueRef safety_crash_err_fn;
1733 LLVMValueRef return_err_fn;1742 LLVMValueRef return_err_fn;
1743 LLVMTypeRef anyframe_fn_type;
17341744
1735 // reminder: hash tables must be initialized before use1745 // reminder: hash tables must be initialized before use
1736 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;1746 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
...@@ -1797,12 +1807,12 @@ struct CodeGen {...@@ -1797,12 +1807,12 @@ struct CodeGen {
1797 ZigType *entry_var;1807 ZigType *entry_var;
1798 ZigType *entry_global_error_set;1808 ZigType *entry_global_error_set;
1799 ZigType *entry_arg_tuple;1809 ZigType *entry_arg_tuple;
1800 ZigType *entry_promise;
1801 ZigType *entry_enum_literal;1810 ZigType *entry_enum_literal;
1811 ZigType *entry_any_frame;
1802 } builtin_types;1812 } builtin_types;
1813
1803 ZigType *align_amt_type;1814 ZigType *align_amt_type;
1804 ZigType *stack_trace_type;1815 ZigType *stack_trace_type;
1805 ZigType *ptr_to_stack_trace_type;
1806 ZigType *err_tag_type;1816 ZigType *err_tag_type;
1807 ZigType *test_fn_type;1817 ZigType *test_fn_type;
18081818
...@@ -1938,6 +1948,7 @@ struct ZigVar {...@@ -1938,6 +1948,7 @@ struct ZigVar {
1938 ZigType *var_type;1948 ZigType *var_type;
1939 LLVMValueRef value_ref;1949 LLVMValueRef value_ref;
1940 IrInstruction *is_comptime;1950 IrInstruction *is_comptime;
1951 IrInstruction *ptr_instruction;
1941 // which node is the declaration of the variable1952 // which node is the declaration of the variable
1942 AstNode *decl_node;1953 AstNode *decl_node;
1943 ZigLLVMDILocalVariable *di_loc_var;1954 ZigLLVMDILocalVariable *di_loc_var;
...@@ -1985,7 +1996,6 @@ enum ScopeId {...@@ -1985,7 +1996,6 @@ enum ScopeId {
1985 ScopeIdSuspend,1996 ScopeIdSuspend,
1986 ScopeIdFnDef,1997 ScopeIdFnDef,
1987 ScopeIdCompTime,1998 ScopeIdCompTime,
1988 ScopeIdCoroPrelude,
1989 ScopeIdRuntime,1999 ScopeIdRuntime,
1990};2000};
19912001
...@@ -2109,7 +2119,6 @@ struct ScopeRuntime {...@@ -2109,7 +2119,6 @@ struct ScopeRuntime {
2109struct ScopeSuspend {2119struct ScopeSuspend {
2110 Scope base;2120 Scope base;
21112121
2112 IrBasicBlock *resume_block;
2113 bool reported_err;2122 bool reported_err;
2114};2123};
21152124
...@@ -2128,12 +2137,6 @@ struct ScopeFnDef {...@@ -2128,12 +2137,6 @@ struct ScopeFnDef {
2128 ZigFn *fn_entry;2137 ZigFn *fn_entry;
2129};2138};
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
2137// synchronized with code in define_builtin_compile_vars2140// synchronized with code in define_builtin_compile_vars
2138enum AtomicOrder {2141enum AtomicOrder {
2139 AtomicOrderUnordered,2142 AtomicOrderUnordered,
...@@ -2231,7 +2234,7 @@ enum IrInstructionId {...@@ -2231,7 +2234,7 @@ enum IrInstructionId {
2231 IrInstructionIdSetRuntimeSafety,2234 IrInstructionIdSetRuntimeSafety,
2232 IrInstructionIdSetFloatMode,2235 IrInstructionIdSetFloatMode,
2233 IrInstructionIdArrayType,2236 IrInstructionIdArrayType,
2234 IrInstructionIdPromiseType,2237 IrInstructionIdAnyFrameType,
2235 IrInstructionIdSliceType,2238 IrInstructionIdSliceType,
2236 IrInstructionIdGlobalAsm,2239 IrInstructionIdGlobalAsm,
2237 IrInstructionIdAsm,2240 IrInstructionIdAsm,
...@@ -2278,7 +2281,10 @@ enum IrInstructionId {...@@ -2278,7 +2281,10 @@ enum IrInstructionId {
2278 IrInstructionIdBreakpoint,2281 IrInstructionIdBreakpoint,
2279 IrInstructionIdReturnAddress,2282 IrInstructionIdReturnAddress,
2280 IrInstructionIdFrameAddress,2283 IrInstructionIdFrameAddress,
2281 IrInstructionIdHandle,2284 IrInstructionIdFrameHandle,
2285 IrInstructionIdFrameType,
2286 IrInstructionIdFrameSizeSrc,
2287 IrInstructionIdFrameSizeGen,
2282 IrInstructionIdAlignOf,2288 IrInstructionIdAlignOf,
2283 IrInstructionIdOverflowOp,2289 IrInstructionIdOverflowOp,
2284 IrInstructionIdTestErrSrc,2290 IrInstructionIdTestErrSrc,
...@@ -2321,35 +2327,16 @@ enum IrInstructionId {...@@ -2321,35 +2327,16 @@ enum IrInstructionId {
2321 IrInstructionIdImplicitCast,2327 IrInstructionIdImplicitCast,
2322 IrInstructionIdResolveResult,2328 IrInstructionIdResolveResult,
2323 IrInstructionIdResetResult,2329 IrInstructionIdResetResult,
2324 IrInstructionIdResultPtr,
2325 IrInstructionIdOpaqueType,2330 IrInstructionIdOpaqueType,
2326 IrInstructionIdSetAlignStack,2331 IrInstructionIdSetAlignStack,
2327 IrInstructionIdArgType,2332 IrInstructionIdArgType,
2328 IrInstructionIdExport,2333 IrInstructionIdExport,
2329 IrInstructionIdErrorReturnTrace,2334 IrInstructionIdErrorReturnTrace,
2330 IrInstructionIdErrorUnion,2335 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,
2345 IrInstructionIdAtomicRmw,2336 IrInstructionIdAtomicRmw,
2346 IrInstructionIdAtomicLoad,2337 IrInstructionIdAtomicLoad,
2347 IrInstructionIdPromiseResultType,
2348 IrInstructionIdAwaitBookkeeping,
2349 IrInstructionIdSaveErrRetAddr,2338 IrInstructionIdSaveErrRetAddr,
2350 IrInstructionIdAddImplicitReturnType,2339 IrInstructionIdAddImplicitReturnType,
2351 IrInstructionIdMergeErrRetTraces,
2352 IrInstructionIdMarkErrRetTracePtr,
2353 IrInstructionIdErrSetCast,2340 IrInstructionIdErrSetCast,
2354 IrInstructionIdToBytes,2341 IrInstructionIdToBytes,
2355 IrInstructionIdFromBytes,2342 IrInstructionIdFromBytes,
...@@ -2365,6 +2352,13 @@ enum IrInstructionId {...@@ -2365,6 +2352,13 @@ enum IrInstructionId {
2365 IrInstructionIdEndExpr,2352 IrInstructionIdEndExpr,
2366 IrInstructionIdPtrOfArrayToSlice,2353 IrInstructionIdPtrOfArrayToSlice,
2367 IrInstructionIdUnionInitNamedField,2354 IrInstructionIdUnionInitNamedField,
2355 IrInstructionIdSuspendBegin,
2356 IrInstructionIdSuspendFinish,
2357 IrInstructionIdAwaitSrc,
2358 IrInstructionIdAwaitGen,
2359 IrInstructionIdResume,
2360 IrInstructionIdSpillBegin,
2361 IrInstructionIdSpillEnd,
2368};2362};
23692363
2370struct IrInstruction {2364struct IrInstruction {
...@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {...@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {
2607 IrInstruction **args;2601 IrInstruction **args;
2608 ResultLoc *result_loc;2602 ResultLoc *result_loc;
26092603
2610 IrInstruction *async_allocator;
2611 IrInstruction *new_stack;2604 IrInstruction *new_stack;
2612 FnInline fn_inline;2605 FnInline fn_inline;
2613 bool is_async;2606 bool is_async;
...@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {...@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {
2622 size_t arg_count;2615 size_t arg_count;
2623 IrInstruction **args;2616 IrInstruction **args;
2624 IrInstruction *result_loc;2617 IrInstruction *result_loc;
2618 IrInstruction *frame_result_loc;
26252619
2626 IrInstruction *async_allocator;
2627 IrInstruction *new_stack;2620 IrInstruction *new_stack;
2628 FnInline fn_inline;2621 FnInline fn_inline;
2629 bool is_async;2622 bool is_async;
...@@ -2639,7 +2632,7 @@ struct IrInstructionConst {...@@ -2639,7 +2632,7 @@ struct IrInstructionConst {
2639struct IrInstructionReturn {2632struct IrInstructionReturn {
2640 IrInstruction base;2633 IrInstruction base;
26412634
2642 IrInstruction *value;2635 IrInstruction *operand;
2643};2636};
26442637
2645enum CastOp {2638enum CastOp {
...@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {...@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {
2744 bool is_allow_zero;2737 bool is_allow_zero;
2745};2738};
27462739
2747struct IrInstructionPromiseType {2740struct IrInstructionAnyFrameType {
2748 IrInstruction base;2741 IrInstruction base;
27492742
2750 IrInstruction *payload_type;2743 IrInstruction *payload_type;
...@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {...@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {
3084 IrInstruction base;3077 IrInstruction base;
3085};3078};
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 {
3088 IrInstruction base;3097 IrInstruction base;
3098
3099 IrInstruction *fn;
3089};3100};
30903101
3091enum IrOverflowOp {3102enum IrOverflowOp {
...@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {...@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {
3127 IrInstruction base;3138 IrInstruction base;
31283139
3129 bool resolve_err_set;3140 bool resolve_err_set;
3141 bool base_ptr_is_payload;
3130 IrInstruction *base_ptr;3142 IrInstruction *base_ptr;
3131};3143};
31323144
...@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {...@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {
3179 IrInstruction **param_types;3191 IrInstruction **param_types;
3180 IrInstruction *align_value;3192 IrInstruction *align_value;
3181 IrInstruction *return_type;3193 IrInstruction *return_type;
3182 IrInstruction *async_allocator_type_value;
3183 bool is_var_args;3194 bool is_var_args;
3184};3195};
31853196
...@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {...@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {
3409 IrInstruction *payload;3420 IrInstruction *payload;
3410};3421};
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
3501struct IrInstructionAtomicRmw {3423struct IrInstructionAtomicRmw {
3502 IrInstruction base;3424 IrInstruction base;
35033425
...@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {...@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {
3519 AtomicOrder resolved_ordering;3441 AtomicOrder resolved_ordering;
3520};3442};
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
3534struct IrInstructionSaveErrRetAddr {3444struct IrInstructionSaveErrRetAddr {
3535 IrInstruction base;3445 IrInstruction base;
3536};3446};
...@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {...@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {
3541 IrInstruction *value;3451 IrInstruction *value;
3542};3452};
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
3558// For float ops which take a single argument3454// For float ops which take a single argument
3559struct IrInstructionFloatOp {3455struct IrInstructionFloatOp {
3560 IrInstruction base;3456 IrInstruction base;
...@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {...@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {
36453541
3646 uint32_t align;3542 uint32_t align;
3647 const char *name_hint;3543 const char *name_hint;
3544 size_t field_index;
3648};3545};
36493546
3650struct IrInstructionEndExpr {3547struct IrInstructionEndExpr {
...@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {...@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {
3692 IrInstruction *result_loc;3589 IrInstruction *result_loc;
3693};3590};
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
3695enum ResultLocId {3642enum ResultLocId {
3696 ResultLocIdInvalid,3643 ResultLocIdInvalid,
3697 ResultLocIdNone,3644 ResultLocIdNone,
...@@ -3775,20 +3722,16 @@ static const size_t maybe_null_index = 1;...@@ -3775,20 +3722,16 @@ static const size_t maybe_null_index = 1;
3775static const size_t err_union_payload_index = 0;3722static const size_t err_union_payload_index = 0;
3776static const size_t err_union_err_index = 1;3723static 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 function3725// label (grep this): [fn_frame_struct_layout]
3779// MUST BE A POWER OF TWO.3726static const size_t frame_fn_ptr_index = 0;
3780static const size_t stack_trace_ptr_count = 32;3727static const size_t frame_resume_index = 1;
37813728static const size_t frame_awaiter_index = 2;
3782// these belong to the async function3729static const size_t frame_ret_start = 3;
3783#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"3730
3784#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"3731// TODO https://github.com/ziglang/zig/issues/3056
3785#define RESULT_FIELD_NAME "result"3732// We require this to be a power of 2 so that we can use shifting rather than
3786#define ASYNC_REALLOC_FIELD_NAME "reallocFn"3733// remainder division.
3787#define ASYNC_SHRINK_FIELD_NAME "shrinkFn"3734static const size_t stack_trace_ptr_count = 32; // Must be a power of 2.
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"
37923735
3793#define NAMESPACE_SEP_CHAR '.'3736#define NAMESPACE_SEP_CHAR '.'
3794#define NAMESPACE_SEP_STR "."3737#define NAMESPACE_SEP_STR "."
...@@ -3811,11 +3754,13 @@ enum FnWalkId {...@@ -3811,11 +3754,13 @@ enum FnWalkId {
38113754
3812struct FnWalkAttrs {3755struct FnWalkAttrs {
3813 ZigFn *fn;3756 ZigFn *fn;
3757 LLVMValueRef llvm_fn;
3814 unsigned gen_i;3758 unsigned gen_i;
3815};3759};
38163760
3817struct FnWalkCall {3761struct FnWalkCall {
3818 ZigList<LLVMValueRef> *gen_param_values;3762 ZigList<LLVMValueRef> *gen_param_values;
3763 ZigList<ZigType *> *gen_param_types;
3819 IrInstructionCallGen *inst;3764 IrInstructionCallGen *inst;
3820 bool is_var_args;3765 bool is_var_args;
3821};3766};
src/analyze.cpp+873-238
...@@ -7,6 +7,7 @@...@@ -7,6 +7,7 @@
77
8#include "analyze.hpp"8#include "analyze.hpp"
9#include "ast_render.hpp"9#include "ast_render.hpp"
10#include "codegen.hpp"
10#include "config.h"11#include "config.h"
11#include "error.hpp"12#include "error.hpp"
12#include "ir.hpp"13#include "ir.hpp"
...@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
31static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
32static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);33static 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
34static bool is_top_level_struct(ZigType *import) {40static bool is_top_level_struct(ZigType *import) {
35 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;41 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
36}42}
...@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {...@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
56 return err;62 return err;
57}63}
5864
59ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {65ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
60 Token fake_token;66 Token fake_token;
61 fake_token.start_line = node->line;67 fake_token.start_line = node->line;
62 fake_token.start_column = node->column;68 fake_token.start_column = node->column;
63 return add_token_error(g, node->owner, &fake_token, msg);69 return add_token_error(g, node->owner, &fake_token, msg);
64}70}
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) {
67 Token fake_token;73 Token fake_token;
68 fake_token.start_line = node->line;74 fake_token.start_line = node->line;
69 fake_token.start_column = node->column;75 fake_token.start_column = node->column;
...@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {...@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
188 return &scope->base;194 return &scope->base;
189}195}
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
197ZigType *get_scope_import(Scope *scope) {197ZigType *get_scope_import(Scope *scope) {
198 while (scope) {198 while (scope) {
199 if (scope->id == ScopeIdDecls) {199 if (scope->id == ScopeIdDecls) {
...@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {...@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
234 return type_entry->data.enumeration.decl_node;234 return type_entry->data.enumeration.decl_node;
235 case ZigTypeIdUnion:235 case ZigTypeIdUnion:
236 return type_entry->data.unionation.decl_node;236 return type_entry->data.unionation.decl_node;
237 case ZigTypeIdFnFrame:
238 return type_entry->data.frame.fn->proto_node;
237 case ZigTypeIdOpaque:239 case ZigTypeIdOpaque:
238 case ZigTypeIdMetaType:240 case ZigTypeIdMetaType:
239 case ZigTypeIdVoid:241 case ZigTypeIdVoid:
...@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {...@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
254 case ZigTypeIdFn:256 case ZigTypeIdFn:
255 case ZigTypeIdBoundFn:257 case ZigTypeIdBoundFn:
256 case ZigTypeIdArgTuple:258 case ZigTypeIdArgTuple:
257 case ZigTypeIdPromise:
258 case ZigTypeIdVector:259 case ZigTypeIdVector:
260 case ZigTypeIdAnyFrame:
259 return nullptr;261 return nullptr;
260 }262 }
261 zig_unreachable();263 zig_unreachable();
...@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {...@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
269 return type_entry->data.structure.resolve_status >= status;271 return type_entry->data.structure.resolve_status >= status;
270 case ZigTypeIdUnion:272 case ZigTypeIdUnion:
271 return type_entry->data.unionation.resolve_status >= status;273 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 }
272 case ZigTypeIdEnum:288 case ZigTypeIdEnum:
273 switch (status) {289 switch (status) {
274 case ResolveStatusUnstarted:290 case ResolveStatusUnstarted:
...@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {...@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
307 case ZigTypeIdFn:323 case ZigTypeIdFn:
308 case ZigTypeIdBoundFn:324 case ZigTypeIdBoundFn:
309 case ZigTypeIdArgTuple:325 case ZigTypeIdArgTuple:
310 case ZigTypeIdPromise:
311 case ZigTypeIdVector:326 case ZigTypeIdVector:
327 case ZigTypeIdAnyFrame:
312 return true;328 return true;
313 }329 }
314 zig_unreachable();330 zig_unreachable();
...@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {...@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
341 return get_int_type(g, false, bits_needed_for_unsigned(x));357 return get_int_type(g, false, bits_needed_for_unsigned(x));
342}358}
343359
344ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {360ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) {
345 if (result_type != nullptr && result_type->promise_parent != nullptr) {361 if (result_type != nullptr && result_type->any_frame_parent != nullptr) {
346 return result_type->promise_parent;362 return result_type->any_frame_parent;
347 } else if (result_type == nullptr && g->builtin_types.entry_promise != nullptr) {363 } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) {
348 return g->builtin_types.entry_promise;364 return g->builtin_types.entry_any_frame;
349 }365 }
350366
351 ZigType *entry = new_type_table_entry(ZigTypeIdPromise);367 ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame);
352 entry->abi_size = g->builtin_types.entry_usize->abi_size;368 entry->abi_size = g->builtin_types.entry_usize->abi_size;
353 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;369 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
354 entry->abi_align = g->builtin_types.entry_usize->abi_align;370 entry->abi_align = g->builtin_types.entry_usize->abi_align;
355 entry->data.promise.result_type = result_type;371 entry->data.any_frame.result_type = result_type;
356 buf_init_from_str(&entry->name, "promise");372 buf_init_from_str(&entry->name, "anyframe");
357 if (result_type != nullptr) {373 if (result_type != nullptr) {
358 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));374 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
359 }375 }
360376
361 if (result_type != nullptr) {377 if (result_type != nullptr) {
362 result_type->promise_parent = entry;378 result_type->any_frame_parent = entry;
363 } else if (result_type == nullptr) {379 } else if (result_type == nullptr) {
364 g->builtin_types.entry_promise = entry;380 g->builtin_types.entry_any_frame = entry;
365 }381 }
366 return entry;382 return entry;
367}383}
...@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {...@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
378 zig_unreachable();394 zig_unreachable();
379}395}
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
381ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,416ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
382 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,417 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
383 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)418 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) {...@@ -490,42 +525,6 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
490 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);525 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
491}526}
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
529ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {528ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
530 if (child_type->optional_parent != nullptr) {529 if (child_type->optional_parent != nullptr) {
531 return child_type->optional_parent;530 return child_type->optional_parent;
...@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa...@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
631 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);630 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);
632 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);631 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);
633 entry->size_in_bits = entry->abi_size * 8;632 entry->size_in_bits = entry->abi_size * 8;
633 entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]);
634 }634 }
635635
636 g->type_table.put(type_id, entry);636 g->type_table.put(type_id, entry);
...@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {...@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
828 zig_unreachable();828 zig_unreachable();
829}829}
830830
831ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {831ZigType *get_stack_trace_type(CodeGen *g) {
832 if (g->stack_trace_type == nullptr) {832 if (g->stack_trace_type == nullptr) {
833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);
835835
836 g->stack_trace_type = stack_trace_type_val->data.x_type;836 g->stack_trace_type = stack_trace_type_val->data.x_type;
837 assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));837 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);
840 }838 }
841 return g->ptr_to_stack_trace_type;839 return g->stack_trace_type;
842}840}
843841
844bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {842bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
...@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
879877
880 // populate the name of the type878 // populate the name of the type
881 buf_resize(&fn_type->name, 0);879 buf_resize(&fn_type->name, 0);
882 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {880 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
883 assert(fn_type_id->async_allocator_type != nullptr);881 buf_appendf(&fn_type->name, "%s", cc_str);
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 }
889 buf_appendf(&fn_type->name, "fn(");882 buf_appendf(&fn_type->name, "fn(");
890 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {883 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
891 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];884 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
...@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {...@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
998ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {991ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
999 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);992 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);
1000 buf_resize(&fn_type->name, 0);993 buf_resize(&fn_type->name, 0);
1001 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {994 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1002 const char *async_allocator_type_str = (fn_type->data.fn.fn_type_id.async_allocator_type == nullptr) ?995 buf_appendf(&fn_type->name, "%s", cc_str);
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 }
1009 buf_appendf(&fn_type->name, "fn(");996 buf_appendf(&fn_type->name, "fn(");
1010 size_t i = 0;997 size_t i = 0;
1011 for (; i < fn_type_id->next_param_index; i += 1) {998 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...@@ -1119,7 +1106,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
1119 case ZigTypeIdBoundFn:1106 case ZigTypeIdBoundFn:
1120 case ZigTypeIdArgTuple:1107 case ZigTypeIdArgTuple:
1121 case ZigTypeIdOpaque:1108 case ZigTypeIdOpaque:
1122 case ZigTypeIdPromise:1109 case ZigTypeIdFnFrame:
1110 case ZigTypeIdAnyFrame:
1123 add_node_error(g, source_node,1111 add_node_error(g, source_node,
1124 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",1112 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
1125 buf_ptr(&type_entry->name)));1113 buf_ptr(&type_entry->name)));
...@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {...@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
1207 case ZigTypeIdErrorSet:1195 case ZigTypeIdErrorSet:
1208 case ZigTypeIdBoundFn:1196 case ZigTypeIdBoundFn:
1209 case ZigTypeIdArgTuple:1197 case ZigTypeIdArgTuple:
1210 case ZigTypeIdPromise:
1211 case ZigTypeIdVoid:1198 case ZigTypeIdVoid:
1199 case ZigTypeIdFnFrame:
1200 case ZigTypeIdAnyFrame:
1212 return false;1201 return false;
1213 case ZigTypeIdOpaque:1202 case ZigTypeIdOpaque:
1214 case ZigTypeIdUnreachable:1203 case ZigTypeIdUnreachable:
...@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1378 case ZigTypeIdEnum:1367 case ZigTypeIdEnum:
1379 case ZigTypeIdUnion:1368 case ZigTypeIdUnion:
1380 case ZigTypeIdFn:1369 case ZigTypeIdFn:
1381 case ZigTypeIdPromise:
1382 case ZigTypeIdVector:1370 case ZigTypeIdVector:
1371 case ZigTypeIdFnFrame:
1372 case ZigTypeIdAnyFrame:
1383 switch (type_requires_comptime(g, type_entry)) {1373 switch (type_requires_comptime(g, type_entry)) {
1384 case ReqCompTimeNo:1374 case ReqCompTimeNo:
1385 break;1375 break;
...@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1474 case ZigTypeIdEnum:1464 case ZigTypeIdEnum:
1475 case ZigTypeIdUnion:1465 case ZigTypeIdUnion:
1476 case ZigTypeIdFn:1466 case ZigTypeIdFn:
1477 case ZigTypeIdPromise:
1478 case ZigTypeIdVector:1467 case ZigTypeIdVector:
1468 case ZigTypeIdFnFrame:
1469 case ZigTypeIdAnyFrame:
1479 switch (type_requires_comptime(g, fn_type_id.return_type)) {1470 switch (type_requires_comptime(g, fn_type_id.return_type)) {
1480 case ReqCompTimeInvalid:1471 case ReqCompTimeInvalid:
1481 return g->builtin_types.entry_invalid;1472 return g->builtin_types.entry_invalid;
...@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1487 break;1478 break;
1488 }1479 }
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
1500 return get_fn_type(g, &fn_type_id);1481 return get_fn_type(g, &fn_type_id);
1501}1482}
15021483
...@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {...@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {
1516 zig_unreachable();1497 zig_unreachable();
1517}1498}
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[],1506static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count,
1521 ZigType *field_types[], size_t field_count)1507 unsigned min_abi_align)
1522{1508{
1523 ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);1509 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...@@ -1530,22 +1516,20 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
1530 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);1516 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
1531 struct_type->data.structure.fields_by_name.init(field_count);1517 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;
1534 for (size_t i = 0; i < field_count; i += 1) {1520 for (size_t i = 0; i < field_count; i += 1) {
1535 TypeStructField *field = &struct_type->data.structure.fields[i];1521 TypeStructField *field = &struct_type->data.structure.fields[i];
1536 field->name = buf_create_from_str(field_names[i]);1522 field->name = buf_create_from_str(fields[i].name);
1537 field->type_entry = field_types[i];1523 field->type_entry = fields[i].ty;
1538 field->src_index = i;1524 field->src_index = i;
1525 field->align = fields[i].align;
15391526
1540 if (type_has_bits(field->type_entry)) {1527 if (type_has_bits(field->type_entry)) {
1541 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));1528 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));
1542 if (field->type_entry->abi_align > abi_align) {1529 unsigned field_abi_align = max(field->align, field->type_entry->abi_align);
1543 abi_align = field->type_entry->abi_align;1530 if (field_abi_align > abi_align) {
1531 abi_align = field_abi_align;
1544 }1532 }
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;
1549 }1533 }
15501534
1551 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);1535 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...@@ -1555,17 +1539,24 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
1555 size_t next_offset = 0;1539 size_t next_offset = 0;
1556 for (size_t i = 0; i < field_count; i += 1) {1540 for (size_t i = 0; i < field_count; i += 1) {
1557 TypeStructField *field = &struct_type->data.structure.fields[i];1541 TypeStructField *field = &struct_type->data.structure.fields[i];
1558 if (field->gen_index == SIZE_MAX)1542 if (!type_has_bits(field->type_entry))
1559 continue;1543 continue;
1544
1560 field->offset = next_offset;1545 field->offset = next_offset;
1546
1547 // find the next non-zero-byte field for offset calculations
1561 size_t next_src_field_index = i + 1;1548 size_t next_src_field_index = i + 1;
1562 for (; next_src_field_index < field_count; next_src_field_index += 1) {1549 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))
1564 break;1551 break;
1565 }
1566 }1552 }
1567 size_t next_abi_align = (next_src_field_index == field_count) ?1553 size_t next_abi_align;
1568 abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->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 }
1569 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);1560 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);
1570 }1561 }
15711562
...@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {...@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26532644
2654 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;2645 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26552646
2656 fn_entry->codegen = g;
2657 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;2647 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
2658 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;2648 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
2659 fn_entry->analyzed_executable.fn_entry = fn_entry;2649 fn_entry->analyzed_executable.fn_entry = fn_entry;
...@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2781 }2771 }
2782 }2772 }
2783 } else {2773 } else {
2774 fn_table_entry->inferred_async_node = inferred_async_none;
2784 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);2775 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
2785 }2776 }
27862777
...@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2802 g->fn_defs.append(fn_table_entry);2793 g->fn_defs.append(fn_table_entry);
2803 }2794 }
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
2805 if (scope_is_root_decls(tld_fn->base.parent_scope) &&2803 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
2806 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))2804 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
2807 {2805 {
...@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3035 case NodeTypeIfErrorExpr:3033 case NodeTypeIfErrorExpr:
3036 case NodeTypeIfOptional:3034 case NodeTypeIfOptional:
3037 case NodeTypeErrorSetDecl:3035 case NodeTypeErrorSetDecl:
3038 case NodeTypeCancel:
3039 case NodeTypeResume:3036 case NodeTypeResume:
3040 case NodeTypeAwaitExpr:3037 case NodeTypeAwaitExpr:
3041 case NodeTypeSuspend:3038 case NodeTypeSuspend:
3042 case NodeTypePromiseType:
3043 case NodeTypeEnumLiteral:3039 case NodeTypeEnumLiteral:
3040 case NodeTypeAnyFrameType:
3044 zig_unreachable();3041 zig_unreachable();
3045 }3042 }
3046}3043}
...@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry...@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
3091 case ZigTypeIdUnion:3088 case ZigTypeIdUnion:
3092 case ZigTypeIdFn:3089 case ZigTypeIdFn:
3093 case ZigTypeIdBoundFn:3090 case ZigTypeIdBoundFn:
3094 case ZigTypeIdPromise:
3095 case ZigTypeIdVector:3091 case ZigTypeIdVector:
3092 case ZigTypeIdFnFrame:
3093 case ZigTypeIdAnyFrame:
3096 return type_entry;3094 return type_entry;
3097 }3095 }
3098 zig_unreachable();3096 zig_unreachable();
...@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {...@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {
3592 case ZigTypeIdBoundFn:3590 case ZigTypeIdBoundFn:
3593 case ZigTypeIdArgTuple:3591 case ZigTypeIdArgTuple:
3594 case ZigTypeIdOpaque:3592 case ZigTypeIdOpaque:
3595 case ZigTypeIdPromise:
3596 case ZigTypeIdVector:3593 case ZigTypeIdVector:
3594 case ZigTypeIdFnFrame:
3595 case ZigTypeIdAnyFrame:
3597 return false;3596 return false;
3598 }3597 }
3599 zig_unreachable();3598 zig_unreachable();
...@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {...@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
3649 case ZigTypeIdInvalid:3648 case ZigTypeIdInvalid:
3650 case ZigTypeIdArgTuple:3649 case ZigTypeIdArgTuple:
3651 case ZigTypeIdOpaque:3650 case ZigTypeIdOpaque:
3652 case ZigTypeIdPromise:
3653 case ZigTypeIdVector:3651 case ZigTypeIdVector:
3652 case ZigTypeIdFnFrame:
3653 case ZigTypeIdAnyFrame:
3654 zig_unreachable();3654 zig_unreachable();
3655 }3655 }
3656 zig_unreachable();3656 zig_unreachable();
...@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {...@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
3659ZigType *get_src_ptr_type(ZigType *type) {3659ZigType *get_src_ptr_type(ZigType *type) {
3660 if (type->id == ZigTypeIdPointer) return type;3660 if (type->id == ZigTypeIdPointer) return type;
3661 if (type->id == ZigTypeIdFn) return type;3661 if (type->id == ZigTypeIdFn) return type;
3662 if (type->id == ZigTypeIdPromise) return type;3662 if (type->id == ZigTypeIdAnyFrame) return type;
3663 if (type->id == ZigTypeIdOptional) {3663 if (type->id == ZigTypeIdOptional) {
3664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {3664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
3665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;3665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
3666 }3666 }
3667 if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;3667 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;
3669 }3669 }
3670 return nullptr;3670 return nullptr;
3671}3671}
...@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {...@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {
3681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);3681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);
3682}3682}
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
3684uint32_t get_ptr_align(CodeGen *g, ZigType *type) {3691uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
3685 ZigType *ptr_type = get_src_ptr_type(type);3692 ZigType *ptr_type = get_src_ptr_type(type);
3686 if (ptr_type->id == ZigTypeIdPointer) {3693 if (ptr_type->id == ZigTypeIdPointer) {
...@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {...@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
3692 // when getting the alignment of `?extern fn() void`.3699 // when getting the alignment of `?extern fn() void`.
3693 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html3700 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html
3694 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;3701 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) {3702 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3696 return get_coro_frame_align_bytes(g);3703 return get_async_frame_align_bytes(g);
3697 } else {3704 } else {
3698 zig_unreachable();3705 zig_unreachable();
3699 }3706 }
...@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {...@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {
3705 return ptr_type->data.pointer.is_const;3712 return ptr_type->data.pointer.is_const;
3706 } else if (ptr_type->id == ZigTypeIdFn) {3713 } else if (ptr_type->id == ZigTypeIdFn) {
3707 return true;3714 return true;
3708 } else if (ptr_type->id == ZigTypeIdPromise) {3715 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3709 return true;3716 return true;
3710 } else {3717 } else {
3711 zig_unreachable();3718 zig_unreachable();
...@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour...@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
3780 return true;3787 return true;
3781}3788}
37823789
3783void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {3790static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) {
3784 ZigType *fn_type = fn_table_entry->type_entry;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;
3785 assert(!fn_type->data.fn.is_generic);3902 assert(!fn_type->data.fn.is_generic);
3786 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;3903 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,3905 ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,
3789 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);3906 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
3790 fn_table_entry->src_implicit_return_type = block_return_type;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) {
3793 assert(g->errors.length > 0);3910 assert(g->errors.length > 0);
3794 fn_table_entry->anal_state = FnAnalStateInvalid;3911 fn->anal_state = FnAnalStateInvalid;
3795 return;3912 return;
3796 }3913 }
37973914
...@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)...@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
3799 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;3916 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3800 if (return_err_set_type->data.error_set.infer_fn != nullptr) {3917 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3801 ZigType *inferred_err_set_type;3918 ZigType *inferred_err_set_type;
3802 if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorSet) {3919 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3803 inferred_err_set_type = fn_table_entry->src_implicit_return_type;3920 inferred_err_set_type = fn->src_implicit_return_type;
3804 } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {3921 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3805 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;3922 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
3806 } else {3923 } else {
3807 add_node_error(g, return_type_node,3924 add_node_error(g, return_type_node,
3808 buf_sprintf("function with inferred error set must return at least one possible error"));3925 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;
3810 return;3927 return;
3811 }3928 }
38123929
3813 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {3930 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
3814 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {3931 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;
3816 return;3933 return;
3817 }3934 }
3818 }3935 }
...@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)...@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
3832 }3949 }
3833 }3950 }
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
3835 if (g->verbose_ir) {3965 if (g->verbose_ir) {
3836 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));3966 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
3837 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);3967 ir_print(g, stderr, &fn->analyzed_executable, 4);
3838 fprintf(stderr, "}\n");3968 fprintf(stderr, "}\n");
3839 }3969 }
38403970 fn->anal_state = FnAnalStateComplete;
3841 fn_table_entry->anal_state = FnAnalStateComplete;
3842}3971}
38433972
3844static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {3973static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
...@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {...@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {
4008 analyze_fn_body(g, fn_entry);4137 analyze_fn_body(g, fn_entry);
4009 }4138 }
4010 }4139 }
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 }
4011}4150}
40124151
4013ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {4152ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
...@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {...@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {
4103 case ZigTypeIdErrorSet:4242 case ZigTypeIdErrorSet:
4104 case ZigTypeIdFn:4243 case ZigTypeIdFn:
4105 case ZigTypeIdEnum:4244 case ZigTypeIdEnum:
4106 case ZigTypeIdPromise:
4107 case ZigTypeIdVector:4245 case ZigTypeIdVector:
4246 case ZigTypeIdAnyFrame:
4108 return false;4247 return false;
4109 case ZigTypeIdArray:4248 case ZigTypeIdArray:
4110 case ZigTypeIdStruct:4249 case ZigTypeIdStruct:
4250 case ZigTypeIdFnFrame:
4111 return type_has_bits(type_entry);4251 return type_has_bits(type_entry);
4112 case ZigTypeIdErrorUnion:4252 case ZigTypeIdErrorUnion:
4113 return type_has_bits(type_entry->data.error_union.payload_type);4253 return type_has_bits(type_entry->data.error_union.payload_type);
...@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {...@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
4143 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;4283 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
4144 result += id->is_var_args ? (uint32_t)1931444534 : 0;4284 result += id->is_var_args ? (uint32_t)1931444534 : 0;
4145 result += hash_ptr(id->return_type);4285 result += hash_ptr(id->return_type);
4146 result += hash_ptr(id->async_allocator_type);
4147 result += id->alignment * 0xd3b3f3e2;4286 result += id->alignment * 0xd3b3f3e2;
4148 for (size_t i = 0; i < id->param_count; i += 1) {4287 for (size_t i = 0; i < id->param_count; i += 1) {
4149 FnTypeParamInfo *info = &id->param_info[i];4288 FnTypeParamInfo *info = &id->param_info[i];
...@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {...@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
4158 a->return_type != b->return_type ||4297 a->return_type != b->return_type ||
4159 a->is_var_args != b->is_var_args ||4298 a->is_var_args != b->is_var_args ||
4160 a->param_count != b->param_count ||4299 a->param_count != b->param_count ||
4161 a->alignment != b->alignment ||4300 a->alignment != b->alignment)
4162 a->async_allocator_type != b->async_allocator_type)
4163 {4301 {
4164 return false;4302 return false;
4165 }4303 }
...@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4321 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);4459 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4322 case ZigTypeIdPointer:4460 case ZigTypeIdPointer:
4323 return hash_const_val_ptr(const_val);4461 return hash_const_val_ptr(const_val);
4324 case ZigTypeIdPromise:
4325 // TODO better hashing algorithm
4326 return 223048345;
4327 case ZigTypeIdUndefined:4462 case ZigTypeIdUndefined:
4328 return 162837799;4463 return 162837799;
4329 case ZigTypeIdNull:4464 case ZigTypeIdNull:
...@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4357 case ZigTypeIdVector:4492 case ZigTypeIdVector:
4358 // TODO better hashing algorithm4493 // TODO better hashing algorithm
4359 return 3647867726;4494 return 3647867726;
4495 case ZigTypeIdFnFrame:
4496 // TODO better hashing algorithm
4497 return 675741936;
4498 case ZigTypeIdAnyFrame:
4499 // TODO better hashing algorithm
4500 return 3747294894;
4360 case ZigTypeIdBoundFn:4501 case ZigTypeIdBoundFn:
4361 case ZigTypeIdInvalid:4502 case ZigTypeIdInvalid:
4362 case ZigTypeIdUnreachable:4503 case ZigTypeIdUnreachable:
...@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {...@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
4389 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {4530 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
4390 assert(a_val->special == ConstValSpecialStatic);4531 assert(a_val->special == ConstValSpecialStatic);
4391 assert(b_val->special == ConstValSpecialStatic);4532 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)) {
4393 return false;4534 return false;
4394 }4535 }
4395 } else {4536 } else {
...@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {...@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
4419 case ZigTypeIdBoundFn:4560 case ZigTypeIdBoundFn:
4420 case ZigTypeIdFn:4561 case ZigTypeIdFn:
4421 case ZigTypeIdOpaque:4562 case ZigTypeIdOpaque:
4422 case ZigTypeIdPromise:
4423 case ZigTypeIdErrorSet:4563 case ZigTypeIdErrorSet:
4424 case ZigTypeIdEnum:4564 case ZigTypeIdEnum:
4565 case ZigTypeIdFnFrame:
4566 case ZigTypeIdAnyFrame:
4425 return false;4567 return false;
44264568
4427 case ZigTypeIdPointer:4569 case ZigTypeIdPointer:
...@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {...@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {
4489 case ZigTypeIdBoundFn:4631 case ZigTypeIdBoundFn:
4490 case ZigTypeIdFn:4632 case ZigTypeIdFn:
4491 case ZigTypeIdOpaque:4633 case ZigTypeIdOpaque:
4492 case ZigTypeIdPromise:
4493 case ZigTypeIdErrorSet:4634 case ZigTypeIdErrorSet:
4494 case ZigTypeIdEnum:4635 case ZigTypeIdEnum:
4495 case ZigTypeIdPointer:4636 case ZigTypeIdPointer:
4496 case ZigTypeIdVector:4637 case ZigTypeIdVector:
4638 case ZigTypeIdFnFrame:
4639 case ZigTypeIdAnyFrame:
4497 return true;4640 return true;
44984641
4499 case ZigTypeIdArray:4642 case ZigTypeIdArray:
...@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {...@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
4624 case ZigTypeIdFn:4767 case ZigTypeIdFn:
4625 case ZigTypeIdBool:4768 case ZigTypeIdBool:
4626 case ZigTypeIdFloat:4769 case ZigTypeIdFloat:
4627 case ZigTypeIdPromise:
4628 case ZigTypeIdErrorUnion:4770 case ZigTypeIdErrorUnion:
4771 case ZigTypeIdFnFrame:
4772 case ZigTypeIdAnyFrame:
4629 return OnePossibleValueNo;4773 return OnePossibleValueNo;
4630 case ZigTypeIdUndefined:4774 case ZigTypeIdUndefined:
4631 case ZigTypeIdNull:4775 case ZigTypeIdNull:
...@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {...@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
4713 case ZigTypeIdFloat:4857 case ZigTypeIdFloat:
4714 case ZigTypeIdVoid:4858 case ZigTypeIdVoid:
4715 case ZigTypeIdUnreachable:4859 case ZigTypeIdUnreachable:
4716 case ZigTypeIdPromise:4860 case ZigTypeIdFnFrame:
4861 case ZigTypeIdAnyFrame:
4717 return ReqCompTimeNo;4862 return ReqCompTimeNo;
4718 }4863 }
4719 zig_unreachable();4864 zig_unreachable();
...@@ -5032,6 +5177,221 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {...@@ -5032,6 +5177,221 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
5032 return type_resolve(g, type_entry, ResolveStatusSizeKnown);5177 return type_resolve(g, type_entry, ResolveStatusSizeKnown);
5033}5178}
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
5035Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {5395Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5036 if (type_is_invalid(ty))5396 if (type_is_invalid(ty))
5037 return ErrorSemanticAnalyzeFail;5397 return ErrorSemanticAnalyzeFail;
...@@ -5056,6 +5416,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {...@@ -5056,6 +5416,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5056 return resolve_enum_zero_bits(g, ty);5416 return resolve_enum_zero_bits(g, ty);
5057 } else if (ty->id == ZigTypeIdUnion) {5417 } else if (ty->id == ZigTypeIdUnion) {
5058 return resolve_union_alignment(g, ty);5418 return resolve_union_alignment(g, ty);
5419 } else if (ty->id == ZigTypeIdFnFrame) {
5420 return resolve_async_frame(g, ty);
5059 }5421 }
5060 return ErrorNone;5422 return ErrorNone;
5061 case ResolveStatusSizeKnown:5423 case ResolveStatusSizeKnown:
...@@ -5065,6 +5427,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {...@@ -5065,6 +5427,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5065 return resolve_enum_zero_bits(g, ty);5427 return resolve_enum_zero_bits(g, ty);
5066 } else if (ty->id == ZigTypeIdUnion) {5428 } else if (ty->id == ZigTypeIdUnion) {
5067 return resolve_union_type(g, ty);5429 return resolve_union_type(g, ty);
5430 } else if (ty->id == ZigTypeIdFnFrame) {
5431 return resolve_async_frame(g, ty);
5068 }5432 }
5069 return ErrorNone;5433 return ErrorNone;
5070 case ResolveStatusLLVMFwdDecl:5434 case ResolveStatusLLVMFwdDecl:
...@@ -5259,6 +5623,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {...@@ -5259,6 +5623,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
5259 return false;5623 return false;
5260 }5624 }
5261 return true;5625 return true;
5626 case ZigTypeIdFnFrame:
5627 zig_panic("TODO");
5628 case ZigTypeIdAnyFrame:
5629 zig_panic("TODO");
5262 case ZigTypeIdUndefined:5630 case ZigTypeIdUndefined:
5263 zig_panic("TODO");5631 zig_panic("TODO");
5264 case ZigTypeIdNull:5632 case ZigTypeIdNull:
...@@ -5279,7 +5647,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {...@@ -5279,7 +5647,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
5279 case ZigTypeIdBoundFn:5647 case ZigTypeIdBoundFn:
5280 case ZigTypeIdInvalid:5648 case ZigTypeIdInvalid:
5281 case ZigTypeIdUnreachable:5649 case ZigTypeIdUnreachable:
5282 case ZigTypeIdPromise:
5283 zig_unreachable();5650 zig_unreachable();
5284 }5651 }
5285 zig_unreachable();5652 zig_unreachable();
...@@ -5612,8 +5979,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {...@@ -5612,8 +5979,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
5612 buf_appendf(buf, "(args value)");5979 buf_appendf(buf, "(args value)");
5613 return;5980 return;
5614 }5981 }
5615 case ZigTypeIdPromise:5982 case ZigTypeIdFnFrame:
5616 zig_unreachable();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
5617 }5990 }
5618 zig_unreachable();5991 zig_unreachable();
5619}5992}
...@@ -5627,6 +6000,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {...@@ -5627,6 +6000,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
5627 entry->llvm_type = LLVMIntType(size_in_bits);6000 entry->llvm_type = LLVMIntType(size_in_bits);
5628 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);6001 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
5629 entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);6002 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 }
5630 }6012 }
56316013
5632 const char u_or_i = is_signed ? 'i' : 'u';6014 const char u_or_i = is_signed ? 'i' : 'u';
...@@ -5660,7 +6042,8 @@ uint32_t type_id_hash(TypeId x) {...@@ -5660,7 +6042,8 @@ uint32_t type_id_hash(TypeId x) {
5660 case ZigTypeIdFn:6042 case ZigTypeIdFn:
5661 case ZigTypeIdBoundFn:6043 case ZigTypeIdBoundFn:
5662 case ZigTypeIdArgTuple:6044 case ZigTypeIdArgTuple:
5663 case ZigTypeIdPromise:6045 case ZigTypeIdFnFrame:
6046 case ZigTypeIdAnyFrame:
5664 zig_unreachable();6047 zig_unreachable();
5665 case ZigTypeIdErrorUnion:6048 case ZigTypeIdErrorUnion:
5666 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);6049 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) {...@@ -5702,7 +6085,6 @@ bool type_id_eql(TypeId a, TypeId b) {
5702 case ZigTypeIdUndefined:6085 case ZigTypeIdUndefined:
5703 case ZigTypeIdNull:6086 case ZigTypeIdNull:
5704 case ZigTypeIdOptional:6087 case ZigTypeIdOptional:
5705 case ZigTypeIdPromise:
5706 case ZigTypeIdErrorSet:6088 case ZigTypeIdErrorSet:
5707 case ZigTypeIdEnum:6089 case ZigTypeIdEnum:
5708 case ZigTypeIdUnion:6090 case ZigTypeIdUnion:
...@@ -5710,6 +6092,8 @@ bool type_id_eql(TypeId a, TypeId b) {...@@ -5710,6 +6092,8 @@ bool type_id_eql(TypeId a, TypeId b) {
5710 case ZigTypeIdBoundFn:6092 case ZigTypeIdBoundFn:
5711 case ZigTypeIdArgTuple:6093 case ZigTypeIdArgTuple:
5712 case ZigTypeIdOpaque:6094 case ZigTypeIdOpaque:
6095 case ZigTypeIdFnFrame:
6096 case ZigTypeIdAnyFrame:
5713 zig_unreachable();6097 zig_unreachable();
5714 case ZigTypeIdErrorUnion:6098 case ZigTypeIdErrorUnion:
5715 return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&6099 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[] = {...@@ -5875,7 +6259,8 @@ static const ZigTypeId all_type_ids[] = {
5875 ZigTypeIdBoundFn,6259 ZigTypeIdBoundFn,
5876 ZigTypeIdArgTuple,6260 ZigTypeIdArgTuple,
5877 ZigTypeIdOpaque,6261 ZigTypeIdOpaque,
5878 ZigTypeIdPromise,6262 ZigTypeIdFnFrame,
6263 ZigTypeIdAnyFrame,
5879 ZigTypeIdVector,6264 ZigTypeIdVector,
5880 ZigTypeIdEnumLiteral,6265 ZigTypeIdEnumLiteral,
5881};6266};
...@@ -5939,12 +6324,14 @@ size_t type_id_index(ZigType *entry) {...@@ -5939,12 +6324,14 @@ size_t type_id_index(ZigType *entry) {
5939 return 20;6324 return 20;
5940 case ZigTypeIdOpaque:6325 case ZigTypeIdOpaque:
5941 return 21;6326 return 21;
5942 case ZigTypeIdPromise:6327 case ZigTypeIdFnFrame:
5943 return 22;6328 return 22;
5944 case ZigTypeIdVector:6329 case ZigTypeIdAnyFrame:
5945 return 23;6330 return 23;
5946 case ZigTypeIdEnumLiteral:6331 case ZigTypeIdVector:
5947 return 24;6332 return 24;
6333 case ZigTypeIdEnumLiteral:
6334 return 25;
5948 }6335 }
5949 zig_unreachable();6336 zig_unreachable();
5950}6337}
...@@ -5999,10 +6386,12 @@ const char *type_id_name(ZigTypeId id) {...@@ -5999,10 +6386,12 @@ const char *type_id_name(ZigTypeId id) {
5999 return "ArgTuple";6386 return "ArgTuple";
6000 case ZigTypeIdOpaque:6387 case ZigTypeIdOpaque:
6001 return "Opaque";6388 return "Opaque";
6002 case ZigTypeIdPromise:
6003 return "Promise";
6004 case ZigTypeIdVector:6389 case ZigTypeIdVector:
6005 return "Vector";6390 return "Vector";
6391 case ZigTypeIdFnFrame:
6392 return "Frame";
6393 case ZigTypeIdAnyFrame:
6394 return "AnyFrame";
6006 }6395 }
6007 zig_unreachable();6396 zig_unreachable();
6008}6397}
...@@ -6067,19 +6456,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {...@@ -6067,19 +6456,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {
6067 return err_set_type->data.error_set.err_count == UINT32_MAX;6456 return err_set_type->data.error_set.err_count == UINT32_MAX;
6068}6457}
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
6077bool type_can_fail(ZigType *type_entry) {6459bool type_can_fail(ZigType *type_entry) {
6078 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;6460 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;
6079}6461}
60806462
6081bool fn_type_can_fail(FnTypeId *fn_type_id) {6463bool 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);
6083}6465}
60846466
6085// ErrorNone - result pointer has the type6467// ErrorNone - result pointer has the type
...@@ -6449,7 +6831,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa...@@ -6449,7 +6831,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
6449 type->data.structure.resolve_status = ResolveStatusLLVMFull;6831 type->data.structure.resolve_status = ResolveStatusLLVMFull;
6450}6832}
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{
6453 assert(struct_type->id == ZigTypeIdStruct);6837 assert(struct_type->id == ZigTypeIdStruct);
6454 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);6838 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);
6455 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);6839 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);
...@@ -6486,10 +6870,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6486,10 +6870,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6486 }6870 }
64876871
6488 size_t field_count = struct_type->data.structure.src_field_count;6872 size_t field_count = struct_type->data.structure.src_field_count;
6489 size_t gen_field_count = struct_type->data.structure.gen_field_count;6873 // Every field could potentially have a generated padding field after it.
6490 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);6874 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count * 2);
64916875
6492 size_t gen_field_index = 0;
6493 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);6876 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
6494 size_t packed_bits_offset = 0;6877 size_t packed_bits_offset = 0;
6495 size_t first_packed_bits_offset_misalign = SIZE_MAX;6878 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...@@ -6497,20 +6880,36 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64976880
6498 // trigger all the recursive get_llvm_type calls6881 // trigger all the recursive get_llvm_type calls
6499 for (size_t i = 0; i < field_count; i += 1) {6882 for (size_t i = 0; i < field_count; i += 1) {
6500 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];6883 TypeStructField *field = &struct_type->data.structure.fields[i];
6501 ZigType *field_type = type_struct_field->type_entry;6884 ZigType *field_type = field->type_entry;
6502 if (!type_has_bits(field_type))6885 if (!type_has_bits(field_type))
6503 continue;6886 continue;
6504 (void)get_llvm_type(g, field_type);6887 (void)get_llvm_type(g, field_type);
6505 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;6888 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;
6506 }6889 }
65076890
6508 for (size_t i = 0; i < field_count; i += 1) {6891 size_t gen_field_index = 0;
6509 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6510 ZigType *field_type = type_struct_field->type_entry;
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;
6512 if (!type_has_bits(field_type))6898 if (!type_has_bits(field_type))
6513 continue;6899 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
6515 if (packed) {6914 if (packed) {
6516 size_t field_size_in_bits = type_size_bits(g, field_type);6915 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...@@ -6537,12 +6936,61 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6537 }6936 }
6538 packed_bits_offset = next_packed_bits_offset;6937 packed_bits_offset = next_packed_bits_offset;
6539 } else {6938 } else {
6540 element_types[gen_field_index] = get_llvm_type(g, field_type);6939 LLVMTypeRef llvm_type;
65416940 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;
6542 gen_field_index += 1;6950 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 }
6543 }6987 }
6544 debug_field_count += 1;6988 debug_field_count += 1;
6545 }6989 }
6990 if (!packed) {
6991 struct_type->data.structure.gen_field_count = gen_field_index;
6992 }
6993
6546 if (first_packed_bits_offset_misalign != SIZE_MAX) {6994 if (first_packed_bits_offset_misalign != SIZE_MAX) {
6547 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;6995 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
6548 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);6996 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...@@ -6551,19 +6999,20 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6551 }6999 }
65527000
6553 if (type_has_bits(struct_type)) {7001 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);
6555 }7004 }
65567005
6557 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);7006 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
6558 size_t debug_field_index = 0;7007 size_t debug_field_index = 0;
6559 for (size_t i = 0; i < field_count; i += 1) {7008 for (size_t i = 0; i < field_count; i += 1) {
6560 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];7009 TypeStructField *field = &struct_type->data.structure.fields[i];
6561 size_t gen_field_index = type_struct_field->gen_index;7010 size_t gen_field_index = field->gen_index;
6562 if (gen_field_index == SIZE_MAX) {7011 if (gen_field_index == SIZE_MAX) {
6563 continue;7012 continue;
6564 }7013 }
65657014
6566 ZigType *field_type = type_struct_field->type_entry;7015 ZigType *field_type = field->type_entry;
65677016
6568 // if the field is a function, actually the debug info should be a pointer.7017 // if the field is a function, actually the debug info should be a pointer.
6569 ZigLLVMDIType *field_di_type;7018 ZigLLVMDIType *field_di_type;
...@@ -6581,13 +7030,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6581,13 +7030,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6581 uint64_t debug_align_in_bits;7030 uint64_t debug_align_in_bits;
6582 uint64_t debug_offset_in_bits;7031 uint64_t debug_offset_in_bits;
6583 if (packed) {7032 if (packed) {
6584 debug_size_in_bits = type_struct_field->type_entry->size_in_bits;7033 debug_size_in_bits = field->type_entry->size_in_bits;
6585 debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;7034 debug_align_in_bits = 8 * field->type_entry->abi_align;
6586 debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;7035 debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host;
6587 } else {7036 } else {
6588 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);7037 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);
6589 debug_align_in_bits = 8 * field_type->abi_align;7038 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;
6591 }7040 }
6592 unsigned line;7041 unsigned line;
6593 if (decl_node != nullptr) {7042 if (decl_node != nullptr) {
...@@ -6597,7 +7046,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6597,7 +7046,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6597 line = 0;7046 line = 0;
6598 }7047 }
6599 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,7048 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),
6601 di_file, line,7050 di_file, line,
6602 debug_size_in_bits,7051 debug_size_in_bits,
6603 debug_align_in_bits,7052 debug_align_in_bits,
...@@ -6838,7 +7287,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta...@@ -6838,7 +7287,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
6838 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;7287 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
6839}7288}
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) {
6842 if (type->llvm_di_type != nullptr) return;7291 if (type->llvm_di_type != nullptr) return;
68437292
6844 if (!type_has_bits(type)) {7293 if (!type_has_bits(type)) {
...@@ -6867,7 +7316,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {...@@ -6867,7 +7316,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
6867 uint64_t debug_align_in_bits = 8*type->abi_align;7316 uint64_t debug_align_in_bits = 8*type->abi_align;
6868 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,7317 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,
6869 debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));7318 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));
6871 } else {7320 } else {
6872 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);7321 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
6873 LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);7322 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) {...@@ -6993,10 +7442,17 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
6993 } else {7442 } else {
6994 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);7443 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
6995 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);7444 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
6996 LLVMTypeRef elem_types[2];7445 LLVMTypeRef elem_types[3];
6997 elem_types[err_union_err_index] = err_set_llvm_type;7446 elem_types[err_union_err_index] = err_set_llvm_type;
6998 elem_types[err_union_payload_index] = payload_llvm_type;7447 elem_types[err_union_payload_index] = payload_llvm_type;
7448
6999 type->llvm_type = LLVMStructType(elem_types, 2, false);7449 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
7001 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);7457 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7002 ZigLLVMDIFile *di_file = nullptr;7458 ZigLLVMDIFile *di_file = nullptr;
...@@ -7068,7 +7524,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {...@@ -7068,7 +7524,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
7068 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);7524 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
7069}7525}
70707526
7071static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {7527static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7072 if (fn_type->llvm_di_type != nullptr) return;7528 if (fn_type->llvm_di_type != nullptr) return;
70737529
7074 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;7530 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) {...@@ -7085,67 +7541,73 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7085 // +1 for maybe first argument the error return trace7541 // +1 for maybe first argument the error return trace
7086 // +2 for maybe arguments async allocator and error code pointer7542 // +2 for maybe arguments async allocator and error code pointer
7087 ZigList<ZigLLVMDIType *> param_di_types = {};7543 ZigList<ZigLLVMDIType *> param_di_types = {};
7088 param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
7089 ZigType *gen_return_type;7544 ZigType *gen_return_type;
7090 if (is_async) {7545 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));
7092 } else if (!type_has_bits(fn_type_id->return_type)) {7548 } else if (!type_has_bits(fn_type_id->return_type)) {
7093 gen_return_type = g->builtin_types.entry_void;7549 gen_return_type = g->builtin_types.entry_void;
7550 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7094 } else if (first_arg_return) {7551 } 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));
7095 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);7554 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
7096 gen_param_types.append(get_llvm_type(g, gen_type));7555 gen_param_types.append(get_llvm_type(g, gen_type));
7097 param_di_types.append(get_llvm_di_type(g, gen_type));7556 param_di_types.append(get_llvm_di_type(g, gen_type));
7098 gen_return_type = g->builtin_types.entry_void;
7099 } else {7557 } else {
7100 gen_return_type = fn_type_id->return_type;7558 gen_return_type = fn_type_id->return_type;
7559 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7101 }7560 }
7102 fn_type->data.fn.gen_return_type = gen_return_type;7561 fn_type->data.fn.gen_return_type = gen_return_type;
71037562
7104 if (prefix_arg_error_return_trace) {7563 if (prefix_arg_error_return_trace && !is_async) {
7105 ZigType *gen_type = get_ptr_to_stack_trace_type(g);7564 ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
7106 gen_param_types.append(get_llvm_type(g, gen_type));7565 gen_param_types.append(get_llvm_type(g, gen_type));
7107 param_di_types.append(get_llvm_di_type(g, gen_type));7566 param_di_types.append(get_llvm_di_type(g, gen_type));
7108 }7567 }
7109 if (is_async) {7568 if (is_async) {
7110 {7569 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(2);
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 }
71167570
7117 {7571 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7118 // error code pointer7572 gen_param_types.append(get_llvm_type(g, frame_type));
7119 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);7573 param_di_types.append(get_llvm_di_type(g, frame_type));
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 }
71247574
7125 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);7575 fn_type->data.fn.gen_param_info[0].src_index = 0;
7126 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {7576 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7127 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];7577 fn_type->data.fn.gen_param_info[0].type = frame_type;
7128 ZigType *type_entry = src_param_info->type;
7129 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
71307578
7131 gen_param_info->src_index = i;7579 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7132 gen_param_info->gen_index = SIZE_MAX;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))7582 fn_type->data.fn.gen_param_info[1].src_index = 1;
7135 continue;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;7592 gen_param_info->src_index = i;
7138 if (handle_is_ptr(type_entry)) {7593 gen_param_info->gen_index = SIZE_MAX;
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));
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 }
7149 }7611 }
71507612
7151 if (is_c_abi) {7613 if (is_c_abi) {
...@@ -7161,6 +7623,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {...@@ -7161,6 +7623,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7161 for (size_t i = 0; i < gen_param_types.length; i += 1) {7623 for (size_t i = 0; i < gen_param_types.length; i += 1) {
7162 assert(gen_param_types.items[i] != nullptr);7624 assert(gen_param_types.items[i] != nullptr);
7163 }7625 }
7626
7164 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),7627 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7165 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);7628 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
7166 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);7629 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) {...@@ -7170,6 +7633,40 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7170 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");7633 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
7171}7634}
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
7173static void resolve_llvm_types_anyerror(CodeGen *g) {7670static void resolve_llvm_types_anyerror(CodeGen *g) {
7174 ZigType *entry = g->builtin_types.entry_global_error_set;7671 ZigType *entry = g->builtin_types.entry_global_error_set;
7175 entry->llvm_type = get_llvm_type(g, g->err_tag_type);7672 entry->llvm_type = get_llvm_type(g, g->err_tag_type);
...@@ -7194,6 +7691,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {...@@ -7194,6 +7691,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
7194 get_llvm_di_type(g, g->err_tag_type), "");7691 get_llvm_di_type(g, g->err_tag_type), "");
7195}7692}
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
7197static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {7835static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
7198 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));7836 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
7199 assert(wanted_resolve_status > ResolveStatusSizeKnown);7837 assert(wanted_resolve_status > ResolveStatusSizeKnown);
...@@ -7219,20 +7857,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7219,20 +7857,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7219 if (type->data.structure.is_slice)7857 if (type->data.structure.is_slice)
7220 return resolve_llvm_types_slice(g, type, wanted_resolve_status);7858 return resolve_llvm_types_slice(g, type, wanted_resolve_status);
7221 else7859 else
7222 return resolve_llvm_types_struct(g, type, wanted_resolve_status);7860 return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr);
7223 case ZigTypeIdEnum:7861 case ZigTypeIdEnum:
7224 return resolve_llvm_types_enum(g, type);7862 return resolve_llvm_types_enum(g, type);
7225 case ZigTypeIdUnion:7863 case ZigTypeIdUnion:
7226 return resolve_llvm_types_union(g, type, wanted_resolve_status);7864 return resolve_llvm_types_union(g, type, wanted_resolve_status);
7227 case ZigTypeIdPointer:7865 case ZigTypeIdPointer:
7228 return resolve_llvm_types_pointer(g, type);7866 return resolve_llvm_types_pointer(g, type, wanted_resolve_status);
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 }
7236 case ZigTypeIdInt:7867 case ZigTypeIdInt:
7237 return resolve_llvm_types_integer(g, type);7868 return resolve_llvm_types_integer(g, type);
7238 case ZigTypeIdOptional:7869 case ZigTypeIdOptional:
...@@ -7242,7 +7873,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7242,7 +7873,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7242 case ZigTypeIdArray:7873 case ZigTypeIdArray:
7243 return resolve_llvm_types_array(g, type);7874 return resolve_llvm_types_array(g, type);
7244 case ZigTypeIdFn:7875 case ZigTypeIdFn:
7245 return resolve_llvm_types_fn(g, type);7876 return resolve_llvm_types_fn_type(g, type);
7246 case ZigTypeIdErrorSet: {7877 case ZigTypeIdErrorSet: {
7247 if (type->llvm_di_type != nullptr) return;7878 if (type->llvm_di_type != nullptr) return;
72487879
...@@ -7261,14 +7892,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7261,14 +7892,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7261 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);7892 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);
7262 return;7893 return;
7263 }7894 }
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);
7264 }7899 }
7265 zig_unreachable();7900 zig_unreachable();
7266}7901}
72677902
7268LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {7903LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {
7269 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));7904 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));
7270 assert(type->abi_size == 0 || type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));7905 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));7906 assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
7272 return type->llvm_type;7907 return type->llvm_type;
7273}7908}
72747909
src/analyze.hpp+8-10
...@@ -11,11 +11,12 @@...@@ -11,11 +11,12 @@
11#include "all_types.hpp"11#include "all_types.hpp"
1212
13void semantic_analyze(CodeGen *g);13void 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);
15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);15ErrorMsg *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);
17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
18ZigType *new_type_table_entry(ZigTypeId id);18ZigType *new_type_table_entry(ZigTypeId id);
19ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
19ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);20ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
20ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,21ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
21 bool is_volatile, PtrLen ptr_len,22 bool is_volatile, PtrLen ptr_len,
...@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);...@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
37ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);38ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
38ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);39ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
39ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);40ZigType *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);
44ZigType *get_test_fn_type(CodeGen *g);41ZigType *get_test_fn_type(CodeGen *g);
42ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
45bool handle_is_ptr(ZigType *type_entry);43bool handle_is_ptr(ZigType *type_entry);
4644
47bool type_has_bits(ZigType *type_entry);45bool type_has_bits(ZigType *type_entry);
...@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v...@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
106void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);104void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);
107105
108void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);106void 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
111ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);108ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
112ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);109ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
...@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);...@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
117ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);114ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
118ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);115ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
119Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);116Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
120Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
121Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);117Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
122118
123void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);119void 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...@@ -199,12 +195,11 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global
199195
200196
201ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);197ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
202ZigType *get_ptr_to_stack_trace_type(CodeGen *g);198ZigType *get_stack_trace_type(CodeGen *g);
203bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);199bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);
204200
205ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);201ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);
206202
207uint32_t get_coro_frame_align_bytes(CodeGen *g);
208bool fn_type_can_fail(FnTypeId *fn_type_id);203bool fn_type_can_fail(FnTypeId *fn_type_id);
209bool type_can_fail(ZigType *type_entry);204bool type_can_fail(ZigType *type_entry);
210bool fn_eval_cacheable(Scope *scope, ZigType *return_type);205bool fn_eval_cacheable(Scope *scope, ZigType *return_type);
...@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);...@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);
251bool is_container(ZigType *type_entry);246bool is_container(ZigType *type_entry);
252ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);247ConstExprValue *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
254#endif252#endif
src/ast_render.cpp+19-26
...@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {...@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {
249 return "IfOptional";249 return "IfOptional";
250 case NodeTypeErrorSetDecl:250 case NodeTypeErrorSetDecl:
251 return "ErrorSetDecl";251 return "ErrorSetDecl";
252 case NodeTypeCancel:
253 return "Cancel";
254 case NodeTypeResume:252 case NodeTypeResume:
255 return "Resume";253 return "Resume";
256 case NodeTypeAwaitExpr:254 case NodeTypeAwaitExpr:
257 return "AwaitExpr";255 return "AwaitExpr";
258 case NodeTypeSuspend:256 case NodeTypeSuspend:
259 return "Suspend";257 return "Suspend";
260 case NodeTypePromiseType:
261 return "PromiseType";
262 case NodeTypePointerType:258 case NodeTypePointerType:
263 return "PointerType";259 return "PointerType";
260 case NodeTypeAnyFrameType:
261 return "AnyFrameType";
264 case NodeTypeEnumLiteral:262 case NodeTypeEnumLiteral:
265 return "EnumLiteral";263 return "EnumLiteral";
266 }264 }
...@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
699 fprintf(ar->f, "@");697 fprintf(ar->f, "@");
700 }698 }
701 if (node->data.fn_call_expr.is_async) {699 if (node->data.fn_call_expr.is_async) {
702 fprintf(ar->f, "async");700 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, " ");
709 }701 }
710 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;702 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
711 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);703 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) {...@@ -862,15 +854,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
862 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);854 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);
863 break;855 break;
864 }856 }
865 case NodeTypePromiseType:857 case NodeTypeAnyFrameType: {
866 {858 fprintf(ar->f, "anyframe");
867 fprintf(ar->f, "promise");859 if (node->data.anyframe_type.payload_type != nullptr) {
868 if (node->data.promise_type.payload_type != nullptr) {860 fprintf(ar->f, "->");
869 fprintf(ar->f, "->");861 render_node_grouped(ar, node->data.anyframe_type.payload_type);
870 render_node_grouped(ar, node->data.promise_type.payload_type);
871 }
872 break;
873 }862 }
863 break;
864 }
874 case NodeTypeErrorType:865 case NodeTypeErrorType:
875 fprintf(ar->f, "anyerror");866 fprintf(ar->f, "anyerror");
876 break;867 break;
...@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1143 fprintf(ar->f, "}");1134 fprintf(ar->f, "}");
1144 break;1135 break;
1145 }1136 }
1146 case NodeTypeCancel:
1147 {
1148 fprintf(ar->f, "cancel ");
1149 render_node_grouped(ar, node->data.cancel_expr.expr);
1150 break;
1151 }
1152 case NodeTypeResume:1137 case NodeTypeResume:
1153 {1138 {
1154 fprintf(ar->f, "resume ");1139 fprintf(ar->f, "resume ");
...@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1163 }1148 }
1164 case NodeTypeSuspend:1149 case NodeTypeSuspend:
1165 {1150 {
1166 fprintf(ar->f, "suspend");
1167 if (node->data.suspend.block != nullptr) {1151 if (node->data.suspend.block != nullptr) {
1152 fprintf(ar->f, "suspend ");
1168 render_node_grouped(ar, node->data.suspend.block);1153 render_node_grouped(ar, node->data.suspend.block);
1154 } else {
1155 fprintf(ar->f, "suspend\n");
1169 }1156 }
1170 break;1157 break;
1171 }1158 }
...@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {...@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {
11911178
1192 render_node_grouped(&ar, node);1179 render_node_grouped(&ar, node);
1193}1180}
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 @@...@@ -24,6 +24,12 @@
24#include <stdio.h>24#include <stdio.h>
25#include <errno.h>25#include <errno.h>
2626
27enum ResumeId {
28 ResumeIdManual,
29 ResumeIdReturn,
30 ResumeIdCall,
31};
32
27static void init_darwin_native(CodeGen *g) {33static void init_darwin_native(CodeGen *g) {
28 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");34 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
29 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");35 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
...@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {...@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
297 zig_unreachable();303 zig_unreachable();
298}304}
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
300static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {336static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
301 if (!g->have_err_ret_tracing) {337 if (!g->have_err_ret_tracing) {
302 return UINT32_MAX;338 return UINT32_MAX;
303 }339 }
304 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {340 if (fn_is_async(fn_table_entry)) {
305 return 0;341 return UINT32_MAX;
306 }342 }
307 ZigType *fn_type = fn_table_entry->type_entry;343 ZigType *fn_type = fn_table_entry->type_entry;
308 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {344 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
...@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {...@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {
343 zig_unreachable();379 zig_unreachable();
344}380}
345381
346static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {382static bool codegen_have_frame_pointer(CodeGen *g) {
347 if (fn_table_entry->llvm_value)383 return g->build_mode == BuildModeDebug;
348 return fn_table_entry->llvm_value;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;
351 Buf *symbol_name;388 Buf *symbol_name;
352 GlobalLinkageId linkage;389 GlobalLinkageId linkage;
353 if (fn_table_entry->body_node == nullptr) {390 if (fn->body_node == nullptr) {
354 symbol_name = unmangled_name;391 symbol_name = unmangled_name;
355 linkage = GlobalLinkageIdStrong;392 linkage = GlobalLinkageIdStrong;
356 } else if (fn_table_entry->export_list.length == 0) {393 } else if (fn->export_list.length == 0) {
357 symbol_name = get_mangled_name(g, unmangled_name, false);394 symbol_name = get_mangled_name(g, unmangled_name, false);
358 linkage = GlobalLinkageIdInternal;395 linkage = GlobalLinkageIdInternal;
359 } else {396 } else {
360 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];397 GlobalExport *fn_export = &fn->export_list.items[0];
361 symbol_name = &fn_export->name;398 symbol_name = &fn_export->name;
362 linkage = fn_export->linkage;399 linkage = fn_export->linkage;
363 }400 }
364401
365 bool external_linkage = linkage != GlobalLinkageIdInternal;402 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;
367 if (cc == CallingConventionStdcall && external_linkage &&404 if (cc == CallingConventionStdcall && external_linkage &&
368 g->zig_target->arch == ZigLLVM_x86)405 g->zig_target->arch == ZigLLVM_x86)
369 {406 {
...@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));408 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372 }409 }
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;
376 // Make the raw_type_ref populated415 // Make the raw_type_ref populated
377 (void)get_llvm_type(g, fn_type);416 resolve_llvm_types_fn(g, fn);
378 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;417 LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
379 if (fn_table_entry->body_node == nullptr) {418 LLVMValueRef llvm_fn = nullptr;
419 if (fn->body_node == nullptr) {
380 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));420 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
381 if (existing_llvm_fn) {421 if (existing_llvm_fn) {
382 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));422 return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
383 return fn_table_entry->llvm_value;
384 } else {423 } else {
385 auto entry = g->exported_symbol_names.maybe_get(symbol_name);424 auto entry = g->exported_symbol_names.maybe_get(symbol_name);
386 if (entry == nullptr) {425 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
389 if (target_is_wasm(g->zig_target)) {428 if (target_is_wasm(g->zig_target)) {
390 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);429 assert(fn->proto_node->type == NodeTypeFnProto);
391 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;430 AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
392 if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {431 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));
394 }433 }
395 }434 }
396 } else {435 } else {
397 assert(entry->value->id == TldIdFn);436 assert(entry->value->id == TldIdFn);
398 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);437 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
399 // Make the raw_type_ref populated438 // 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);
401 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),440 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);441 tld_fn->fn_entry->raw_type_ref);
403 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,442 llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0));
404 LLVMPointerType(fn_llvm_type, 0));443 return llvm_fn;
405 return fn_table_entry->llvm_value;
406 }444 }
407 }445 }
408 } else {446 } else {
409 if (fn_table_entry->llvm_value == nullptr) {447 if (llvm_fn == nullptr) {
410 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);448 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
411 }449 }
412450
413 for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {451 for (size_t i = 1; i < fn->export_list.length; i += 1) {
414 GlobalExport *fn_export = &fn_table_entry->export_list.items[i];452 GlobalExport *fn_export = &fn->export_list.items[i];
415 LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value),453 LLVMAddAlias(g->module, LLVMTypeOf(llvm_fn), llvm_fn, buf_ptr(&fn_export->name));
416 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
417 }454 }
418 }455 }
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) {
422 case FnInlineAlways:458 case FnInlineAlways:
423 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");459 addLLVMFnAttr(llvm_fn, "alwaysinline");
424 g->inline_fns.append(fn_table_entry);460 g->inline_fns.append(fn);
425 break;461 break;
426 case FnInlineNever:462 case FnInlineNever:
427 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");463 addLLVMFnAttr(llvm_fn, "noinline");
428 break;464 break;
429 case FnInlineAuto:465 case FnInlineAuto:
430 if (fn_table_entry->alignstack_value != 0) {466 if (fn->alignstack_value != 0) {
431 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");467 addLLVMFnAttr(llvm_fn, "noinline");
432 }468 }
433 break;469 break;
434 }470 }
435471
436 if (cc == CallingConventionNaked) {472 if (cc == CallingConventionNaked) {
437 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");473 addLLVMFnAttr(llvm_fn, "naked");
438 } else {474 } else {
439 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));475 LLVMSetFunctionCallConv(llvm_fn, 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");
444 }476 }
445477
446 bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;478 bool want_cold = fn->is_cold || cc == CallingConventionCold;
447 if (want_cold) {479 if (want_cold) {
448 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);480 ZigLLVMAddFunctionAttrCold(llvm_fn);
449 }481 }
450482
451483
452 LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage));484 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
453485
454 if (linkage == GlobalLinkageIdInternal) {486 if (linkage == GlobalLinkageIdInternal) {
455 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);487 LLVMSetUnnamedAddr(llvm_fn, true);
456 }488 }
457489
458 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;490 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
459 if (return_type->id == ZigTypeIdUnreachable) {491 if (return_type->id == ZigTypeIdUnreachable) {
460 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");492 addLLVMFnAttr(llvm_fn, "noreturn");
461 }493 }
462494
463 if (fn_table_entry->body_node != nullptr) {495 if (fn->body_node != nullptr) {
464 maybe_export_dll(g, fn_table_entry->llvm_value, linkage);496 maybe_export_dll(g, llvm_fn, linkage);
465497
466 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&498 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
467 g->build_mode != BuildModeSmallRelease &&499 g->build_mode != BuildModeSmallRelease &&
468 !fn_table_entry->def_scope->safety_off;500 !fn->def_scope->safety_off;
469 if (want_fn_safety) {501 if (want_fn_safety) {
470 if (g->libc_link_lib != nullptr) {502 if (g->libc_link_lib != nullptr) {
471 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");503 addLLVMFnAttr(llvm_fn, "sspstrong");
472 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");504 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
473 }505 }
474 }506 }
475 if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) {507 if (g->have_stack_probing && !fn->def_scope->safety_off) {
476 addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack");508 addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack");
477 }509 }
478 } else {510 } else {
479 maybe_import_dll(g, fn_table_entry->llvm_value, linkage);511 maybe_import_dll(g, llvm_fn, linkage);
480 }512 }
481513
482 if (fn_table_entry->alignstack_value != 0) {514 if (fn->alignstack_value != 0) {
483 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value);515 addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value);
484 }516 }
485517
486 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");518 addLLVMFnAttr(llvm_fn, "nounwind");
487 add_uwtable_attr(g, fn_table_entry->llvm_value);519 add_uwtable_attr(g, llvm_fn);
488 addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");520 addLLVMFnAttr(llvm_fn, "nobuiltin");
489 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {521 if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) {
490 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");522 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim", "true");
491 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);523 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim-non-leaf", nullptr);
492 }524 }
493 if (fn_table_entry->section_name) {525 if (fn->section_name) {
494 LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));526 LLVMSetSection(llvm_fn, buf_ptr(fn->section_name));
495 }527 }
496 if (fn_table_entry->align_bytes > 0) {528 if (fn->align_bytes > 0) {
497 LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);529 LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes);
498 } else {530 } else {
499 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives531 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
500 // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling532 // "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) {...@@ -502,36 +534,50 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
502 // use the ABI alignment, which is fine.534 // use the ABI alignment, which is fine.
503 }535 }
504536
505 unsigned init_gen_i = 0;537 if (is_async) {
506 if (!type_has_bits(return_type)) {538 addLLVMArgAttr(llvm_fn, 0, "nonnull");
507 // nothing to do539 } else {
508 } else if (type_is_nonnull_ptr(return_type)) {540 unsigned init_gen_i = 0;
509 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");541 if (!type_has_bits(return_type)) {
510 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {542 // nothing to do
511 // Sret pointers must not be address 0543 } else if (type_is_nonnull_ptr(return_type)) {
512 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");544 addLLVMAttr(llvm_fn, 0, "nonnull");
513 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");545 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
514 if (cc_want_sret_attr(cc)) {546 // Sret pointers must not be address 0
515 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");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;
516 }553 }
517 init_gen_i = 1;
518 }
519554
520 // set parameter attributes555 // set parameter attributes
521 FnWalk fn_walk = {};556 FnWalk fn_walk = {};
522 fn_walk.id = FnWalkIdAttrs;557 fn_walk.id = FnWalkIdAttrs;
523 fn_walk.data.attrs.fn = fn_table_entry;558 fn_walk.data.attrs.fn = fn;
524 fn_walk.data.attrs.gen_i = init_gen_i;559 fn_walk.data.attrs.llvm_fn = llvm_fn;
525 walk_function_params(g, fn_type, &fn_walk);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);563 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn);
528 if (err_ret_trace_arg_index != UINT32_MAX) {564 if (err_ret_trace_arg_index != UINT32_MAX) {
529 // Error return trace memory is in the stack, which is impossible to be at address 0565 // Error return trace memory is in the stack, which is impossible to be at address 0
530 // on any architecture.566 // on any architecture.
531 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");567 addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull");
568 }
532 }569 }
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;
535}581}
536582
537static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {583static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
...@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
559 unsigned flags = ZigLLVM_DIFlags_StaticMember;605 unsigned flags = ZigLLVM_DIFlags_StaticMember;
560 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);606 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);
561 assert(fn_di_scope != nullptr);607 assert(fn_di_scope != nullptr);
608 assert(fn_table_entry->raw_di_type != nullptr);
562 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,609 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
563 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",610 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
564 import->data.structure.root_struct->di_file, line_number,611 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,
566 is_definition, scope_line, flags, is_optimized, nullptr);613 is_definition, scope_line, flags, is_optimized, nullptr);
567614
568 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);615 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
...@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
597 case ScopeIdLoop:644 case ScopeIdLoop:
598 case ScopeIdSuspend:645 case ScopeIdSuspend:
599 case ScopeIdCompTime:646 case ScopeIdCompTime:
600 case ScopeIdCoroPrelude:
601 case ScopeIdRuntime:647 case ScopeIdRuntime:
602 return get_di_scope(g, scope->parent);648 return get_di_scope(g, scope->parent);
603 }649 }
...@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {...@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
798 return false;844 return false;
799}845}
800846
801static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {847static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) {
802 // TODO memoize848 // TODO memoize
803 Scope *scope = instruction->scope;
804 while (scope) {849 while (scope) {
805 if (scope->id == ScopeIdBlock) {850 if (scope->id == ScopeIdBlock) {
806 ScopeBlock *block_scope = (ScopeBlock *)scope;851 ScopeBlock *block_scope = (ScopeBlock *)scope;
...@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {...@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
818 g->build_mode != BuildModeSmallRelease);863 g->build_mode != BuildModeSmallRelease);
819}864}
820865
866static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
867 return ir_want_runtime_safety_scope(g, instruction->scope);
868}
869
821static Buf *panic_msg_buf(PanicMsgId msg_id) {870static Buf *panic_msg_buf(PanicMsgId msg_id) {
822 switch (msg_id) {871 switch (msg_id) {
823 case PanicMsgIdCount:872 case PanicMsgIdCount:
...@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
858 return buf_create_from_str("integer part of floating point value out of bounds");907 return buf_create_from_str("integer part of floating point value out of bounds");
859 case PanicMsgIdPtrCastNull:908 case PanicMsgIdPtrCastNull:
860 return buf_create_from_str("cast causes pointer to be null");909 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");
861 }922 }
862 zig_unreachable();923 zig_unreachable();
863}924}
...@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
882 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));943 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));
883}944}
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
885static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {950static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
886 assert(g->panic_fn != nullptr);951 assert(g->panic_fn != nullptr);
887 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);952 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
888 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);953 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
889 if (stack_trace_arg == nullptr) {954 if (stack_trace_arg == nullptr) {
890 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);955 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
891 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
892 }956 }
893 LLVMValueRef args[] = {957 LLVMValueRef args[] = {
894 msg_arg,958 msg_arg,
...@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {...@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
904 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);968 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
905}969}
906970
907static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {971static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) {
908 if (ir_want_runtime_safety(g, source_instruction)) {972 if (ir_want_runtime_safety_scope(g, source_scope)) {
909 gen_safety_crash(g, msg_id);973 gen_safety_crash(g, msg_id);
910 } else {974 } else {
911 LLVMBuildUnreachable(g->builder);975 LLVMBuildUnreachable(g->builder);
912 }976 }
913}977}
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
915static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {983static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
916 if (g->stacksave_fn_val)984 if (g->stacksave_fn_val)
917 return g->stacksave_fn_val;985 return g->stacksave_fn_val;
...@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {...@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
959 return g->write_register_fn_val;1027 return g->write_register_fn_val;
960}1028}
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
1133static LLVMValueRef get_return_address_fn_val(CodeGen *g) {1030static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1134 if (g->return_address_fn_val)1031 if (g->return_address_fn_val)
1135 return g->return_address_fn_val;1032 return g->return_address_fn_val;
...@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1149 return g->add_error_return_trace_addr_fn_val;1046 return g->add_error_return_trace_addr_fn_val;
11501047
1151 LLVMTypeRef arg_types[] = {1048 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)),
1153 g->builtin_types.entry_usize->llvm_type,1050 g->builtin_types.entry_usize->llvm_type,
1154 };1051 };
1155 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);1052 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) {...@@ -1164,7 +1061,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1164 // Error return trace memory is in the stack, which is impossible to be at address 01061 // Error return trace memory is in the stack, which is impossible to be at address 0
1165 // on any architecture.1062 // on any architecture.
1166 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");1063 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1167 if (g->build_mode == BuildModeDebug) {1064 if (codegen_have_frame_pointer(g)) {
1168 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1065 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1169 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1066 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1170 }1067 }
...@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1222 return fn_val;1119 return fn_val;
1223}1120}
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
1359static LLVMValueRef get_return_err_fn(CodeGen *g) {1122static LLVMValueRef get_return_err_fn(CodeGen *g) {
1360 if (g->return_err_fn != nullptr)1123 if (g->return_err_fn != nullptr)
1361 return g->return_err_fn;1124 return g->return_err_fn;
...@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13641127
1365 LLVMTypeRef arg_types[] = {1128 LLVMTypeRef arg_types[] = {
1366 // error return trace pointer1129 // 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)),
1368 };1131 };
1369 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1132 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
13701133
...@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1376 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1139 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1377 addLLVMFnAttr(fn_val, "nounwind");1140 addLLVMFnAttr(fn_val, "nounwind");
1378 add_uwtable_attr(g, fn_val);1141 add_uwtable_attr(g, fn_val);
1379 // Error return trace memory is in the stack, which is impossible to be at address 01142 if (codegen_have_frame_pointer(g)) {
1380 // on any architecture.
1381 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1382 if (g->build_mode == BuildModeDebug) {
1383 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1143 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1384 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1144 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1385 }1145 }
...@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1400 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");1160 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1401 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");1161 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);
1403 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };1174 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1404 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");1175 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1405 LLVMBuildRetVoid(g->builder);1176 LLVMBuildRetVoid(g->builder);
...@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1434 LLVMTypeRef fn_type_ref;1205 LLVMTypeRef fn_type_ref;
1435 if (g->have_err_ret_tracing) {1206 if (g->have_err_ret_tracing) {
1436 LLVMTypeRef arg_types[] = {1207 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)),
1438 get_llvm_type(g, g->err_tag_type),1209 get_llvm_type(g, g->err_tag_type),
1439 };1210 };
1440 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);1211 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
...@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1451 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1222 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1452 addLLVMFnAttr(fn_val, "nounwind");1223 addLLVMFnAttr(fn_val, "nounwind");
1453 add_uwtable_attr(g, fn_val);1224 add_uwtable_attr(g, fn_val);
1454 if (g->build_mode == BuildModeDebug) {1225 if (codegen_have_frame_pointer(g)) {
1455 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1226 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1456 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1227 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1457 }1228 }
...@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1543 return fn_val;1314 return fn_val;
1544}1315}
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
1558static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {1317static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
1559 if (!g->have_err_ret_tracing) {1318 if (!g->have_err_ret_tracing) {
1560 return nullptr;1319 return nullptr;
1561 }1320 }
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 }
1565 if (g->cur_err_ret_trace_val_stack != nullptr) {1321 if (g->cur_err_ret_trace_val_stack != nullptr) {
1566 return g->cur_err_ret_trace_val_stack;1322 return g->cur_err_ret_trace_val_stack;
1567 }1323 }
...@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc...@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
1574 if (g->have_err_ret_tracing) {1330 if (g->have_err_ret_tracing) {
1575 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);1331 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
1576 if (err_ret_trace_val == nullptr) {1332 if (err_ret_trace_val == nullptr) {
1577 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);1333 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
1578 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
1579 }1334 }
1580 LLVMValueRef args[] = {1335 LLVMValueRef args[] = {
1581 err_ret_trace_val,1336 err_ret_trace_val,
...@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {...@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
1820 }1575 }
1821}1576}
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,
1824 LLVMValueRef value)1579 LLVMValueRef value)
1825{1580{
1826 assert(ptr_type->id == ZigTypeIdPointer);1581 assert(ptr_type->id == ZigTypeIdPointer);
1827 ZigType *child_type = ptr_type->data.pointer.child_type;1582 ZigType *child_type = ptr_type->data.pointer.child_type;
18281583
1829 if (!type_has_bits(child_type))1584 if (!type_has_bits(child_type))
1830 return nullptr;1585 return;
18311586
1832 if (handle_is_ptr(child_type)) {1587 if (handle_is_ptr(child_type)) {
1833 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);1588 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);
...@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty...@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
1847 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,1602 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,
1848 LLVMConstInt(usize->llvm_type, size_bytes, false),1603 LLVMConstInt(usize->llvm_type, size_bytes, false),
1849 ptr_type->data.pointer.is_volatile);1604 ptr_type->data.pointer.is_volatile);
1850 return nullptr;1605 return;
1851 }1606 }
18521607
1853 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;1608 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
1854 if (host_int_bytes == 0) {1609 if (host_int_bytes == 0) {
1855 gen_store(g, value, ptr, ptr_type);1610 gen_store(g, value, ptr, ptr_type);
1856 return nullptr;1611 return;
1857 }1612 }
18581613
1859 bool big_endian = g->is_big_endian;1614 bool big_endian = g->is_big_endian;
...@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty...@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
1883 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");1638 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
18841639
1885 gen_store(g, ored_value, ptr, ptr_type);1640 gen_store(g, ored_value, ptr, ptr_type);
1886 return nullptr;1641 return;
1887}1642}
18881643
1889static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {1644static 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_...@@ -1967,7 +1722,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
1967 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];1722 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1968 ty = param_info->type;1723 ty = param_info->type;
1969 source_node = fn_walk->data.attrs.fn->proto_node;1724 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;
1971 break;1726 break;
1972 case FnWalkIdCall: {1727 case FnWalkIdCall: {
1973 if (src_i >= fn_walk->data.call.inst->arg_count)1728 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_...@@ -2149,10 +1904,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
2149 }1904 }
2150 case FnWalkIdInits: {1905 case FnWalkIdInits: {
2151 clear_debug_source_node(g);1906 clear_debug_source_node(g);
2152 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);1907 if (!fn_is_async(fn_walk->data.inits.fn)) {
2153 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);1908 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2154 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");1909 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2155 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);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 }
2156 if (var->decl_node) {1913 if (var->decl_node) {
2157 gen_var_debug_decl(g, var);1914 gen_var_debug_decl(g, var);
2158 }1915 }
...@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2201 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);1958 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
2202 assert(param_value);1959 assert(param_value);
2203 fn_walk->data.call.gen_param_values->append(param_value);1960 fn_walk->data.call.gen_param_values->append(param_value);
1961 fn_walk->data.call.gen_param_types->append(param_type);
2204 }1962 }
2205 }1963 }
2206 return;1964 return;
...@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22161974
2217 switch (fn_walk->id) {1975 switch (fn_walk->id) {
2218 case FnWalkIdAttrs: {1976 case FnWalkIdAttrs: {
2219 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;1977 LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn;
2220 bool is_byval = gen_info->is_byval;1978 bool is_byval = gen_info->is_byval;
2221 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];1979 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) {...@@ -2245,7 +2003,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2245 assert(variable);2003 assert(variable);
2246 assert(variable->value_ref);2004 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)) {
2249 clear_debug_source_node(g);2007 clear_debug_source_node(g);
2250 ZigType *fn_type = fn_table_entry->type_entry;2008 ZigType *fn_type = fn_table_entry->type_entry;
2251 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;2009 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) {...@@ -2271,48 +2029,357 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2271 }2029 }
2272}2030}
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}
2274static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,2170static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
2275 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)2171 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
2276{2172{
2277 assert(g->have_err_ret_tracing);2173 assert(g->have_err_ret_tracing);
22782174
2279 LLVMValueRef return_err_fn = get_return_err_fn(g);2175 LLVMValueRef return_err_fn = get_return_err_fn(g);
2280 LLVMValueRef args[] = {2176 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2281 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,
2282 };
2283 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
2284 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");2178 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);
2286}2205}
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
2289 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {2356 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) {
2291 LLVMBuildRetVoid(g->builder);2358 LLVMBuildRetVoid(g->builder);
2292 return nullptr;2359 return nullptr;
2293 }2360 }
2294 assert(g->cur_ret_ptr);2361 assert(g->cur_ret_ptr);
2295 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,2362 src_assert(instruction->operand->value.special != ConstValSpecialRuntime,
2296 return_instruction->base.source_node);2363 instruction->base.source_node);
2297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2364 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2298 ZigType *return_type = return_instruction->value->value.type;2365 ZigType *return_type = instruction->operand->value.type;
2299 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);2366 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
2300 LLVMBuildRetVoid(g->builder);2367 LLVMBuildRetVoid(g->builder);
2301 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&2368 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
2302 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))2369 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
2303 {2370 {
2304 if (return_instruction->value == nullptr) {2371 if (instruction->operand == nullptr) {
2305 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");2372 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
2306 LLVMBuildRet(g->builder, by_val_value);2373 LLVMBuildRet(g->builder, by_val_value);
2307 } else {2374 } else {
2308 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2375 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2309 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");2376 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
2310 LLVMBuildRet(g->builder, by_val_value);2377 LLVMBuildRet(g->builder, by_val_value);
2311 }2378 }
2312 } else if (return_instruction->value == nullptr) {2379 } else if (instruction->operand == nullptr) {
2313 LLVMBuildRetVoid(g->builder);2380 LLVMBuildRetVoid(g->builder);
2314 } else {2381 } else {
2315 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2382 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2316 LLVMBuildRet(g->builder, value);2383 LLVMBuildRet(g->builder, value);
2317 }2384 }
2318 return nullptr;2385 return nullptr;
...@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI...@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
3242 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");3309 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
3243}3310}
32443311
3245static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {3312static void render_decl_var(CodeGen *g, ZigVar *var) {
3246 ZigVar *var = instruction->var;
3247
3248 if (!type_has_bits(var->var_type))3313 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);
3252 gen_var_debug_decl(g, var);3317 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);
3253 return nullptr;3323 return nullptr;
3254}3324}
32553325
...@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn...@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
3467static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,3537static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,
3468 IrInstructionReturnPtr *instruction)3538 IrInstructionReturnPtr *instruction)
3469{3539{
3470 src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type),3540 if (!type_has_bits(instruction->base.value.type))
3471 instruction->base.source_node);3541 return nullptr;
3542 src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node);
3472 return g->cur_ret_ptr;3543 return g->cur_ret_ptr;
3473}3544}
34743545
...@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
3566 }3637 }
3567}3638}
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
3589static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {3640static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
3590 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");3641 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
3591 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");3642 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) {...@@ -3623,16 +3674,124 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
3623 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);3674 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
3624}3675}
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
3626static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {3780static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3781 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3782
3627 LLVMValueRef fn_val;3783 LLVMValueRef fn_val;
3628 ZigType *fn_type;3784 ZigType *fn_type;
3785 bool callee_is_async;
3629 if (instruction->fn_entry) {3786 if (instruction->fn_entry) {
3630 fn_val = fn_llvm_value(g, instruction->fn_entry);3787 fn_val = fn_llvm_value(g, instruction->fn_entry);
3631 fn_type = instruction->fn_entry->type_entry;3788 fn_type = instruction->fn_entry->type_entry;
3789 callee_is_async = fn_is_async(instruction->fn_entry);
3632 } else {3790 } else {
3633 assert(instruction->fn_ref);3791 assert(instruction->fn_ref);
3634 fn_val = ir_llvm_value(g, instruction->fn_ref);3792 fn_val = ir_llvm_value(g, instruction->fn_ref);
3635 fn_type = instruction->fn_ref->value.type;3793 fn_type = instruction->fn_ref->value.type;
3794 callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync;
3636 }3795 }
36373796
3638 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;3797 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...@@ -3643,27 +3802,154 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3643 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;3802 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
36443803
3645 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);3804 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);
3647 bool is_var_args = fn_type_id->is_var_args;3806 bool is_var_args = fn_type_id->is_var_args;
3648 ZigList<LLVMValueRef> gen_param_values = {};3807 ZigList<LLVMValueRef> gen_param_values = {};
3808 ZigList<ZigType *> gen_param_types = {};
3649 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;3809 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3650 if (first_arg_ret) {3810 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3651 gen_param_values.append(result_loc);3811 LLVMValueRef frame_result_loc;
3652 }3812 LLVMValueRef awaiter_init_val;
3653 if (prefix_arg_err_ret_stack) {3813 LLVMValueRef ret_ptr;
3654 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));3814 if (callee_is_async) {
3655 }3815 if (instruction->is_async) {
3656 if (instruction->is_async) {3816 if (instruction->new_stack == nullptr) {
3657 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));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, "");3841 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3660 gen_param_values.append(err_val_ptr);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 }
3661 }3946 }
3662 FnWalk fn_walk = {};3947 FnWalk fn_walk = {};
3663 fn_walk.id = FnWalkIdCall;3948 fn_walk.id = FnWalkIdCall;
3664 fn_walk.data.call.inst = instruction;3949 fn_walk.data.call.inst = instruction;
3665 fn_walk.data.call.is_var_args = is_var_args;3950 fn_walk.data.call.is_var_args = is_var_args;
3666 fn_walk.data.call.gen_param_values = &gen_param_values;3951 fn_walk.data.call.gen_param_values = &gen_param_values;
3952 fn_walk.data.call.gen_param_types = &gen_param_types;
3667 walk_function_params(g, fn_type, &fn_walk);3953 walk_function_params(g, fn_type, &fn_walk);
36683954
3669 ZigLLVM_FnInline fn_inline;3955 ZigLLVM_FnInline fn_inline;
...@@ -3679,12 +3965,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3679,12 +3965,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3679 break;3965 break;
3680 }3966 }
36813967
3682 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);3968 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3683 LLVMValueRef result;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
3685 if (instruction->new_stack == nullptr) {4028 if (instruction->new_stack == nullptr) {
3686 result = ZigLLVMBuildCall(g->builder, fn_val,4029 result = ZigLLVMBuildCall(g->builder, fn_val,
3687 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");4030 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");
3688 } else {4033 } else {
3689 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);4034 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
3690 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);4035 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
...@@ -3697,13 +4042,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3697,13 +4042,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3697 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");4042 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
3698 }4043 }
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
3707 if (src_return_type->id == ZigTypeIdUnreachable) {4045 if (src_return_type->id == ZigTypeIdUnreachable) {
3708 return LLVMBuildUnreachable(g->builder);4046 return LLVMBuildUnreachable(g->builder);
3709 } else if (!ret_has_bits) {4047 } else if (!ret_has_bits) {
...@@ -4200,7 +4538,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -4200,7 +4538,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
4200 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));4538 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
4201 addLLVMFnAttr(fn_val, "nounwind");4539 addLLVMFnAttr(fn_val, "nounwind");
4202 add_uwtable_attr(g, fn_val);4540 add_uwtable_attr(g, fn_val);
4203 if (g->build_mode == BuildModeDebug) {4541 if (codegen_have_frame_pointer(g)) {
4204 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");4542 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
4205 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);4543 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
4206 }4544 }
...@@ -4347,10 +4685,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -4347,10 +4685,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
4347 {4685 {
4348 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;4686 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
4349 ptr_val = target_val;4687 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");
4354 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {4688 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
4355 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;4689 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
4356 align_bytes = get_ptr_align(g, slice_ptr_type);4690 align_bytes = get_ptr_align(g, slice_ptr_type);
...@@ -4388,26 +4722,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu...@@ -4388,26 +4722,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
4388{4722{
4389 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);4723 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
4390 if (cur_err_ret_trace_val == nullptr) {4724 if (cur_err_ret_trace_val == nullptr) {
4391 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);4725 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
4392 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
4393 }4726 }
4394 return cur_err_ret_trace_val;4727 return cur_err_ret_trace_val;
4395}4728}
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
4411static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {4730static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
4412 switch (atomic_order) {4731 switch (atomic_order) {
4413 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;4732 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
...@@ -4722,24 +5041,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable...@@ -4722,24 +5041,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
4722 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");5041 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
4723}5042}
47245043
4725static LLVMValueRef get_handle_fn_val(CodeGen *g) {5044static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable, IrInstructionFrameHandle *instruction) {
4726 if (g->coro_frame_fn_val)5045 return g->cur_frame_ptr;
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, "");
4743}5046}
47445047
4745static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {5048static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
...@@ -5005,248 +5308,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst...@@ -5005,248 +5308,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
5005 return nullptr;5308 return nullptr;
5006}5309}
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
5250static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,5311static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
5251 IrInstructionAtomicRmw *instruction)5312 IrInstructionAtomicRmw *instruction)
5252{5313{
...@@ -5263,14 +5324,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -5263,14 +5324,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
5263 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);5324 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
52645325
5265 if (get_codegen_ptr_type(operand_type) == nullptr) {5326 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);
5267 }5328 }
52685329
5269 // it's a pointer but we need to treat it as an int5330 // it's a pointer but we need to treat it as an int
5270 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,5331 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
5271 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");5332 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
5272 LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, "");5333 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);
5274 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");5336 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
5275}5337}
52765338
...@@ -5284,27 +5346,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,...@@ -5284,27 +5346,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
5284 return load_inst;5346 return load_inst;
5285}5347}
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
5308static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {5349static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
5309 LLVMValueRef op = ir_llvm_value(g, instruction->op1);5350 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
5310 assert(instruction->base.value.type->id == ZigTypeIdFloat);5351 assert(instruction->base.value.type->id == ZigTypeIdFloat);
...@@ -5424,6 +5465,174 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab...@@ -5424,6 +5465,174 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
5424 return nullptr;5465 return nullptr;
5425}5466}
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
5427static void set_debug_location(CodeGen *g, IrInstruction *instruction) {5636static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
5428 AstNode *source_node = instruction->source_node;5637 AstNode *source_node = instruction->source_node;
5429 Scope *scope = instruction->scope;5638 Scope *scope = instruction->scope;
...@@ -5445,7 +5654,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5445,7 +5654,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5445 case IrInstructionIdSetRuntimeSafety:5654 case IrInstructionIdSetRuntimeSafety:
5446 case IrInstructionIdSetFloatMode:5655 case IrInstructionIdSetFloatMode:
5447 case IrInstructionIdArrayType:5656 case IrInstructionIdArrayType:
5448 case IrInstructionIdPromiseType:5657 case IrInstructionIdAnyFrameType:
5449 case IrInstructionIdSliceType:5658 case IrInstructionIdSliceType:
5450 case IrInstructionIdSizeOf:5659 case IrInstructionIdSizeOf:
5451 case IrInstructionIdSwitchTarget:5660 case IrInstructionIdSwitchTarget:
...@@ -5485,8 +5694,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5485,8 +5694,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5485 case IrInstructionIdTagType:5694 case IrInstructionIdTagType:
5486 case IrInstructionIdExport:5695 case IrInstructionIdExport:
5487 case IrInstructionIdErrorUnion:5696 case IrInstructionIdErrorUnion:
5488 case IrInstructionIdPromiseResultType:
5489 case IrInstructionIdAwaitBookkeeping:
5490 case IrInstructionIdAddImplicitReturnType:5697 case IrInstructionIdAddImplicitReturnType:
5491 case IrInstructionIdIntCast:5698 case IrInstructionIdIntCast:
5492 case IrInstructionIdFloatCast:5699 case IrInstructionIdFloatCast:
...@@ -5508,17 +5715,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5508,17 +5715,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5508 case IrInstructionIdCallSrc:5715 case IrInstructionIdCallSrc:
5509 case IrInstructionIdAllocaSrc:5716 case IrInstructionIdAllocaSrc:
5510 case IrInstructionIdEndExpr:5717 case IrInstructionIdEndExpr:
5511 case IrInstructionIdAllocaGen:
5512 case IrInstructionIdImplicitCast:5718 case IrInstructionIdImplicitCast:
5513 case IrInstructionIdResolveResult:5719 case IrInstructionIdResolveResult:
5514 case IrInstructionIdResetResult:5720 case IrInstructionIdResetResult:
5515 case IrInstructionIdResultPtr:
5516 case IrInstructionIdContainerInitList:5721 case IrInstructionIdContainerInitList:
5517 case IrInstructionIdSliceSrc:5722 case IrInstructionIdSliceSrc:
5518 case IrInstructionIdRef:5723 case IrInstructionIdRef:
5519 case IrInstructionIdBitCastSrc:5724 case IrInstructionIdBitCastSrc:
5520 case IrInstructionIdTestErrSrc:5725 case IrInstructionIdTestErrSrc:
5521 case IrInstructionIdUnionInitNamedField:5726 case IrInstructionIdUnionInitNamedField:
5727 case IrInstructionIdFrameType:
5728 case IrInstructionIdFrameSizeSrc:
5729 case IrInstructionIdAllocaGen:
5730 case IrInstructionIdAwaitSrc:
5522 zig_unreachable();5731 zig_unreachable();
55235732
5524 case IrInstructionIdDeclVarGen:5733 case IrInstructionIdDeclVarGen:
...@@ -5597,8 +5806,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5597,8 +5806,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5597 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);5806 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
5598 case IrInstructionIdFrameAddress:5807 case IrInstructionIdFrameAddress:
5599 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);5808 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
5600 case IrInstructionIdHandle:5809 case IrInstructionIdFrameHandle:
5601 return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);5810 return ir_render_handle(g, executable, (IrInstructionFrameHandle *)instruction);
5602 case IrInstructionIdOverflowOp:5811 case IrInstructionIdOverflowOp:
5603 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);5812 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
5604 case IrInstructionIdTestErrGen:5813 case IrInstructionIdTestErrGen:
...@@ -5641,44 +5850,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5641,44 +5850,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5641 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);5850 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
5642 case IrInstructionIdErrorReturnTrace:5851 case IrInstructionIdErrorReturnTrace:
5643 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);5852 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);
5672 case IrInstructionIdAtomicRmw:5853 case IrInstructionIdAtomicRmw:
5673 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);5854 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
5674 case IrInstructionIdAtomicLoad:5855 case IrInstructionIdAtomicLoad:
5675 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);5856 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
5676 case IrInstructionIdSaveErrRetAddr:5857 case IrInstructionIdSaveErrRetAddr:
5677 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);5858 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);
5682 case IrInstructionIdFloatOp:5859 case IrInstructionIdFloatOp:
5683 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);5860 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
5684 case IrInstructionIdMulAdd:5861 case IrInstructionIdMulAdd:
...@@ -5695,6 +5872,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5695,6 +5872,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5695 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);5872 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
5696 case IrInstructionIdPtrOfArrayToSlice:5873 case IrInstructionIdPtrOfArrayToSlice:
5697 return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction);5874 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);
5698 }5889 }
5699 zig_unreachable();5890 zig_unreachable();
5700}5891}
...@@ -5704,6 +5895,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {...@@ -5704,6 +5895,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
57045895
5705 IrExecutable *executable = &fn_entry->analyzed_executable;5896 IrExecutable *executable = &fn_entry->analyzed_executable;
5706 assert(executable->basic_block_list.length > 0);5897 assert(executable->basic_block_list.length > 0);
5898
5707 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {5899 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
5708 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);5900 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
5709 assert(current_block->llvm_block);5901 assert(current_block->llvm_block);
...@@ -5894,7 +6086,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -5894,7 +6086,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5894 case ZigTypeIdPointer:6086 case ZigTypeIdPointer:
5895 case ZigTypeIdFn:6087 case ZigTypeIdFn:
5896 case ZigTypeIdOptional:6088 case ZigTypeIdOptional:
5897 case ZigTypeIdPromise:
5898 {6089 {
5899 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");6090 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
5900 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type);6091 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...@@ -5957,7 +6148,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5957 }6148 }
5958 return val;6149 return val;
5959 }6150 }
59606151 case ZigTypeIdFnFrame:
6152 zig_panic("TODO bit pack an async function frame");
6153 case ZigTypeIdAnyFrame:
6154 zig_panic("TODO bit pack an anyframe");
5961 }6155 }
5962 zig_unreachable();6156 zig_unreachable();
5963}6157}
...@@ -6110,6 +6304,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6110,6 +6304,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6110 break;6304 break;
6111 }6305 }
61126306
6307 if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull)))
6308 zig_unreachable();
6309
6113 switch (type_entry->id) {6310 switch (type_entry->id) {
6114 case ZigTypeIdInt:6311 case ZigTypeIdInt:
6115 return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint);6312 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...@@ -6181,6 +6378,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6181 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);6378 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
6182 size_t src_field_count = type_entry->data.structure.src_field_count;6379 size_t src_field_count = type_entry->data.structure.src_field_count;
6183 bool make_unnamed_struct = false;6380 bool make_unnamed_struct = false;
6381 assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull);
6184 if (type_entry->data.structure.layout == ContainerLayoutPacked) {6382 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
6185 size_t src_field_index = 0;6383 size_t src_field_index = 0;
6186 while (src_field_index < src_field_count) {6384 while (src_field_index < src_field_count) {
...@@ -6250,6 +6448,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6250,6 +6448,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6250 LLVMValueRef val = gen_const_val(g, field_val, "");6448 LLVMValueRef val = gen_const_val(g, field_val, "");
6251 fields[type_struct_field->gen_index] = val;6449 fields[type_struct_field->gen_index] = val;
6252 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);6450 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 }
6253 }6467 }
6254 }6468 }
6255 if (make_unnamed_struct) {6469 if (make_unnamed_struct) {
...@@ -6437,13 +6651,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6437,13 +6651,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6437 err_payload_value = gen_const_val(g, payload_val, "");6651 err_payload_value = gen_const_val(g, payload_val, "");
6438 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);6652 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);
6439 }6653 }
6440 LLVMValueRef fields[2];6654 LLVMValueRef fields[3];
6441 fields[err_union_err_index] = err_tag_value;6655 fields[err_union_err_index] = err_tag_value;
6442 fields[err_union_payload_index] = err_payload_value;6656 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 }
6443 if (make_unnamed_struct) {6662 if (make_unnamed_struct) {
6444 return LLVMConstStruct(fields, 2, false);6663 return LLVMConstStruct(fields, field_count, false);
6445 } else {6664 } else {
6446 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);6665 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count);
6447 }6666 }
6448 }6667 }
6449 }6668 }
...@@ -6460,9 +6679,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6460,9 +6679,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6460 case ZigTypeIdBoundFn:6679 case ZigTypeIdBoundFn:
6461 case ZigTypeIdArgTuple:6680 case ZigTypeIdArgTuple:
6462 case ZigTypeIdOpaque:6681 case ZigTypeIdOpaque:
6463 case ZigTypeIdPromise:
6464 zig_unreachable();6682 zig_unreachable();
64656683 case ZigTypeIdFnFrame:
6684 zig_panic("TODO");
6685 case ZigTypeIdAnyFrame:
6686 zig_panic("TODO");
6466 }6687 }
6467 zig_unreachable();6688 zig_unreachable();
6468}6689}
...@@ -6546,12 +6767,20 @@ static void generate_error_name_table(CodeGen *g) {...@@ -6546,12 +6767,20 @@ static void generate_error_name_table(CodeGen *g) {
6546static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {6767static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {
6547 IrExecutable *executable = &fn->analyzed_executable;6768 IrExecutable *executable = &fn->analyzed_executable;
6548 assert(executable->basic_block_list.length > 0);6769 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 }
6549 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {6776 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
6550 IrBasicBlock *bb = executable->basic_block_list.at(block_i);6777 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;
6552 }6782 }
6553 IrBasicBlock *entry_bb = executable->basic_block_list.at(0);6783 LLVMPositionBuilderAtEnd(g->builder, first_bb);
6554 LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
6555}6784}
65566785
6557static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,6786static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
...@@ -6728,13 +6957,19 @@ static void do_code_gen(CodeGen *g) {...@@ -6728,13 +6957,19 @@ static void do_code_gen(CodeGen *g) {
6728 build_all_basic_blocks(g, fn_table_entry);6957 build_all_basic_blocks(g, fn_table_entry);
6729 clear_debug_source_node(g);6958 clear_debug_source_node(g);
67306959
6731 if (want_sret) {6960 bool is_async = fn_is_async(fn_table_entry);
6732 g->cur_ret_ptr = LLVMGetParam(fn, 0);6961
6733 } else if (handle_is_ptr(fn_type_id->return_type)) {6962 if (is_async) {
6734 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);6963 g->cur_frame_ptr = LLVMGetParam(fn, 0);
6735 // TODO add debug info variable for this
6736 } else {6964 } 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 }
6738 }6973 }
67396974
6740 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);6975 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) {...@@ -6746,39 +6981,41 @@ static void do_code_gen(CodeGen *g) {
6746 }6981 }
67476982
6748 // error return tracing setup6983 // error return tracing setup
6749 bool is_async = cc == CallingConventionAsync;6984 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
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;6985 !is_async && !have_err_ret_trace_arg;
6751 LLVMValueRef err_ret_array_val = nullptr;6986 LLVMValueRef err_ret_array_val = nullptr;
6752 if (have_err_ret_trace_stack) {6987 if (have_err_ret_trace_stack) {
6753 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);6988 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
6754 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));6989 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_type6991 (void)get_llvm_type(g, get_stack_trace_type(g));
6757 (void)get_ptr_to_stack_trace_type(g);6992 g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace",
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));6993 get_abi_alignment(g, g->stack_trace_type));
6759 } else {6994 } else {
6760 g->cur_err_ret_trace_val_stack = nullptr;6995 g->cur_err_ret_trace_val_stack = nullptr;
6761 }6996 }
67626997
6763 // allocate temporary stack data6998 if (!is_async) {
6764 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {6999 // allocate temporary stack data
6765 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);7000 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6766 ZigType *ptr_type = instruction->base.value.type;7001 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6767 assert(ptr_type->id == ZigTypeIdPointer);7002 ZigType *ptr_type = instruction->base.value.type;
6768 ZigType *child_type = ptr_type->data.pointer.child_type;7003 assert(ptr_type->id == ZigTypeIdPointer);
6769 if (!type_has_bits(child_type))7004 ZigType *child_type = ptr_type->data.pointer.child_type;
6770 continue;7005 if (!type_has_bits(child_type))
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 {
6777 continue;7006 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 }
6778 }7015 }
7016 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
7017 get_ptr_align(g, ptr_type));
6779 }7018 }
6780 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6781 get_ptr_align(g, ptr_type));
6782 }7019 }
67837020
6784 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);7021 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
...@@ -6816,7 +7053,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6816,7 +7053,7 @@ static void do_code_gen(CodeGen *g) {
6816 } else if (is_c_abi) {7053 } else if (is_c_abi) {
6817 fn_walk_var.data.vars.var = var;7054 fn_walk_var.data.vars.var = var;
6818 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);7055 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) {
6820 ZigType *gen_type;7057 ZigType *gen_type;
6821 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];7058 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
6822 assert(gen_info->gen_index != SIZE_MAX);7059 assert(gen_info->gen_index != SIZE_MAX);
...@@ -6867,14 +7104,76 @@ static void do_code_gen(CodeGen *g) {...@@ -6867,14 +7104,76 @@ static void do_code_gen(CodeGen *g) {
6867 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));7104 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
6868 }7105 }
68697106
6870 // create debug variable declarations for parameters7107 if (is_async) {
6871 // rely on the first variables in the variable_list being parameters.7108 (void)get_llvm_type(g, fn_table_entry->frame_type);
6872 FnWalk fn_walk_init = {};7109 g->cur_resume_block_count = 0;
6873 fn_walk_init.id = FnWalkIdInits;7110
6874 fn_walk_init.data.inits.fn = fn_table_entry;7111 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
6875 fn_walk_init.data.inits.llvm_fn = fn;7112 LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
6876 fn_walk_init.data.inits.gen_i = gen_i_init;7113 ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
6877 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);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
6879 ir_render(g, fn_table_entry);7178 ir_render(g, fn_table_entry);
68807179
...@@ -6893,8 +7192,6 @@ static void do_code_gen(CodeGen *g) {...@@ -6893,8 +7192,6 @@ static void do_code_gen(CodeGen *g) {
6893 LLVMDumpModule(g->module);7192 LLVMDumpModule(g->module);
6894 }7193 }
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.
6898#ifndef NDEBUG7195#ifndef NDEBUG
6899 char *error = nullptr;7196 char *error = nullptr;
6900 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);7197 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
...@@ -7163,16 +7460,8 @@ static void define_builtin_types(CodeGen *g) {...@@ -7163,16 +7460,8 @@ static void define_builtin_types(CodeGen *g) {
71637460
7164 g->primitive_type_table.put(&entry->name, entry);7461 g->primitive_type_table.put(&entry->name, entry);
7165 }7462 }
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 }
7173}7463}
71747464
7175
7176static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {7465static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {
7177 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);7466 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
7178 buf_init_from_str(&builtin_fn->name, name);7467 buf_init_from_str(&builtin_fn->name, name);
...@@ -7185,8 +7474,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char...@@ -7185,8 +7474,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
7185static void define_builtin_fns(CodeGen *g) {7474static void define_builtin_fns(CodeGen *g) {
7186 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);7475 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
7187 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);7476 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
7188 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7189 create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
7190 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);7477 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
7191 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);7478 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
7192 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);7479 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
...@@ -7262,13 +7549,13 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7262,13 +7549,13 @@ static void define_builtin_fns(CodeGen *g) {
7262 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);7549 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
7263 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);7550 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
7264 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);7551 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7265 //Needs library support on Windows7552 create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7266 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7267 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);7553 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
7268 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);7554 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
7269 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);7555 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
7270 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);7556 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
7271 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);7557 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
7558 create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
7272 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);7559 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
7273 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);7560 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
7274 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);7561 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
...@@ -7287,6 +7574,10 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7287,6 +7574,10 @@ static void define_builtin_fns(CodeGen *g) {
7287 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);7574 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
7288 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);7575 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
7289 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);7576 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);
7290}7581}
72917582
7292static const char *bool_to_str(bool b) {7583static const char *bool_to_str(bool b) {
...@@ -7598,7 +7889,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7598,7 +7889,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7598 " BoundFn: Fn,\n"7889 " BoundFn: Fn,\n"
7599 " ArgTuple: void,\n"7890 " ArgTuple: void,\n"
7600 " Opaque: void,\n"7891 " Opaque: void,\n"
7601 " Promise: Promise,\n"7892 " Frame: void,\n"
7893 " AnyFrame: AnyFrame,\n"
7602 " Vector: Vector,\n"7894 " Vector: Vector,\n"
7603 " EnumLiteral: void,\n"7895 " EnumLiteral: void,\n"
7604 "\n\n"7896 "\n\n"
...@@ -7711,11 +8003,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7711,11 +8003,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7711 " is_generic: bool,\n"8003 " is_generic: bool,\n"
7712 " is_var_args: bool,\n"8004 " is_var_args: bool,\n"
7713 " return_type: ?type,\n"8005 " return_type: ?type,\n"
7714 " async_allocator_type: ?type,\n"
7715 " args: []FnArg,\n"8006 " args: []FnArg,\n"
7716 " };\n"8007 " };\n"
7717 "\n"8008 "\n"
7718 " pub const Promise = struct {\n"8009 " pub const AnyFrame = struct {\n"
7719 " child: ?type,\n"8010 " child: ?type,\n"
7720 " };\n"8011 " };\n"
7721 "\n"8012 "\n"
...@@ -8308,6 +8599,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8308,6 +8599,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8308 args.append("-g");8599 args.append("-g");
8309 }8600 }
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
8311 switch (g->build_mode) {8608 switch (g->build_mode) {
8312 case BuildModeDebug:8609 case BuildModeDebug:
8313 // windows c runtime requires -D_DEBUG if using debug libraries8610 // 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...@@ -8320,7 +8617,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8320 } else {8617 } else {
8321 args.append("-fno-stack-protector");8618 args.append("-fno-stack-protector");
8322 }8619 }
8323 args.append("-fno-omit-frame-pointer");
8324 break;8620 break;
8325 case BuildModeSafeRelease:8621 case BuildModeSafeRelease:
8326 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather8622 // 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...@@ -8334,7 +8630,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8334 } else {8630 } else {
8335 args.append("-fno-stack-protector");8631 args.append("-fno-stack-protector");
8336 }8632 }
8337 args.append("-fomit-frame-pointer");
8338 break;8633 break;
8339 case BuildModeFastRelease:8634 case BuildModeFastRelease:
8340 args.append("-DNDEBUG");8635 args.append("-DNDEBUG");
...@@ -8345,13 +8640,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8345,13 +8640,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8345 // running in -O2 and thus the -O3 path has been tested less.8640 // running in -O2 and thus the -O3 path has been tested less.
8346 args.append("-O2");8641 args.append("-O2");
8347 args.append("-fno-stack-protector");8642 args.append("-fno-stack-protector");
8348 args.append("-fomit-frame-pointer");
8349 break;8643 break;
8350 case BuildModeSmallRelease:8644 case BuildModeSmallRelease:
8351 args.append("-DNDEBUG");8645 args.append("-DNDEBUG");
8352 args.append("-Os");8646 args.append("-Os");
8353 args.append("-fno-stack-protector");8647 args.append("-fno-stack-protector");
8354 args.append("-fomit-frame-pointer");
8355 break;8648 break;
8356 }8649 }
83578650
...@@ -8878,7 +9171,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e...@@ -8878,7 +9171,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
8878 case ZigTypeIdArgTuple:9171 case ZigTypeIdArgTuple:
8879 case ZigTypeIdErrorUnion:9172 case ZigTypeIdErrorUnion:
8880 case ZigTypeIdErrorSet:9173 case ZigTypeIdErrorSet:
8881 case ZigTypeIdPromise:9174 case ZigTypeIdFnFrame:
9175 case ZigTypeIdAnyFrame:
8882 zig_unreachable();9176 zig_unreachable();
8883 case ZigTypeIdVoid:9177 case ZigTypeIdVoid:
8884 case ZigTypeIdUnreachable:9178 case ZigTypeIdUnreachable:
...@@ -9062,7 +9356,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -9062,7 +9356,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
9062 case ZigTypeIdUndefined:9356 case ZigTypeIdUndefined:
9063 case ZigTypeIdNull:9357 case ZigTypeIdNull:
9064 case ZigTypeIdArgTuple:9358 case ZigTypeIdArgTuple:
9065 case ZigTypeIdPromise:9359 case ZigTypeIdFnFrame:
9360 case ZigTypeIdAnyFrame:
9066 zig_unreachable();9361 zig_unreachable();
9067 }9362 }
9068}9363}
...@@ -9229,9 +9524,11 @@ static void gen_h_file(CodeGen *g) {...@@ -9229,9 +9524,11 @@ static void gen_h_file(CodeGen *g) {
9229 case ZigTypeIdArgTuple:9524 case ZigTypeIdArgTuple:
9230 case ZigTypeIdOptional:9525 case ZigTypeIdOptional:
9231 case ZigTypeIdFn:9526 case ZigTypeIdFn:
9232 case ZigTypeIdPromise:
9233 case ZigTypeIdVector:9527 case ZigTypeIdVector:
9528 case ZigTypeIdFnFrame:
9529 case ZigTypeIdAnyFrame:
9234 zig_unreachable();9530 zig_unreachable();
9531
9235 case ZigTypeIdEnum:9532 case ZigTypeIdEnum:
9236 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {9533 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
9237 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));9534 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...@@ -9770,3 +10067,18 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
9770 return g;10067 return g;
9771}10068}
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);...@@ -61,5 +61,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g);
61TargetSubsystem detect_subsystem(CodeGen *g);61TargetSubsystem detect_subsystem(CodeGen *g);
6262
63void codegen_release_caches(CodeGen *codegen);63void 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
65#endif67#endif
src/ir.cpp+853-1711
...@@ -26,6 +26,7 @@ struct IrBuilder {...@@ -26,6 +26,7 @@ struct IrBuilder {
26 CodeGen *codegen;26 CodeGen *codegen;
27 IrExecutable *exec;27 IrExecutable *exec;
28 IrBasicBlock *current_basic_block;28 IrBasicBlock *current_basic_block;
29 AstNode *main_block_node;
29};30};
3031
31struct IrAnalyze {32struct IrAnalyze {
...@@ -99,7 +100,6 @@ struct ConstCastOnly {...@@ -99,7 +100,6 @@ struct ConstCastOnly {
99 ConstCastErrUnionErrSetMismatch *error_union_error_set;100 ConstCastErrUnionErrSetMismatch *error_union_error_set;
100 ConstCastTypeMismatch *type_mismatch;101 ConstCastTypeMismatch *type_mismatch;
101 ConstCastOnly *return_type;102 ConstCastOnly *return_type;
102 ConstCastOnly *async_allocator_type;
103 ConstCastOnly *null_wrap_ptr_child;103 ConstCastOnly *null_wrap_ptr_child;
104 ConstCastArg fn_arg;104 ConstCastArg fn_arg;
105 ConstCastArgNoAlias arg_no_alias;105 ConstCastArgNoAlias arg_no_alias;
...@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {...@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
305 case ZigTypeIdBoundFn:305 case ZigTypeIdBoundFn:
306 case ZigTypeIdErrorSet:306 case ZigTypeIdErrorSet:
307 case ZigTypeIdOpaque:307 case ZigTypeIdOpaque:
308 case ZigTypeIdAnyFrame:
308 return true;309 return true;
309 case ZigTypeIdFloat:310 case ZigTypeIdFloat:
310 return a->data.floating.bit_count == b->data.floating.bit_count;311 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) {...@@ -319,8 +320,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
319 case ZigTypeIdUnion:320 case ZigTypeIdUnion:
320 case ZigTypeIdFn:321 case ZigTypeIdFn:
321 case ZigTypeIdArgTuple:322 case ZigTypeIdArgTuple:
322 case ZigTypeIdPromise:
323 case ZigTypeIdVector:323 case ZigTypeIdVector:
324 case ZigTypeIdFnFrame:
324 return false;325 return false;
325 }326 }
326 zig_unreachable();327 zig_unreachable();
...@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {...@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
565 return IrInstructionIdArrayType;566 return IrInstructionIdArrayType;
566}567}
567568
568static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {569static constexpr IrInstructionId ir_instruction_id(IrInstructionAnyFrameType *) {
569 return IrInstructionIdPromiseType;570 return IrInstructionIdAnyFrameType;
570}571}
571572
572static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {573static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
...@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)...@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
761 return IrInstructionIdFrameAddress;762 return IrInstructionIdFrameAddress;
762}763}
763764
764static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {765static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameHandle *) {
765 return IrInstructionIdHandle;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;
766}779}
767780
768static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {781static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
...@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {...@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {
933 return IrInstructionIdResetResult;946 return IrInstructionIdResetResult;
934}947}
935948
936static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) {
937 return IrInstructionIdResultPtr;
938}
939
940static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {949static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
941 return IrInstructionIdPtrOfArrayToSlice;950 return IrInstructionIdPtrOfArrayToSlice;
942}951}
...@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {...@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
961 return IrInstructionIdErrorUnion;970 return IrInstructionIdErrorUnion;
962}971}
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
1020static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {973static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
1021 return IrInstructionIdAtomicRmw;974 return IrInstructionIdAtomicRmw;
1022}975}
...@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {...@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
1025 return IrInstructionIdAtomicLoad;978 return IrInstructionIdAtomicLoad;
1026}979}
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
1036static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {981static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
1037 return IrInstructionIdSaveErrRetAddr;982 return IrInstructionIdSaveErrRetAddr;
1038}983}
...@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur...@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
1041 return IrInstructionIdAddImplicitReturnType;986 return IrInstructionIdAddImplicitReturnType;
1042}987}
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
1052static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {989static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1053 return IrInstructionIdFloatOp;990 return IrInstructionIdFloatOp;
1054}991}
...@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi...@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi
1097 return IrInstructionIdUnionInitNamedField;1034 return IrInstructionIdUnionInitNamedField;
1098}1035}
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
1100template<typename T>1065template<typename T>
1101static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1066static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1102 T *special_instruction = allocate<T>(1);1067 T *special_instruction = allocate<T>(1);
...@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so...@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
1149}1114}
11501115
1151static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,1116static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,
1152 IrInstruction *return_value)1117 IrInstruction *operand)
1153{1118{
1154 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);1119 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);
1155 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;1120 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
1156 return_instruction->base.value.special = ConstValSpecialStatic;1121 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
1161 return &return_instruction->base;1126 return &return_instruction->base;
1162}1127}
...@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode...@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode
1214 return &const_instruction->base;1179 return &const_instruction->base;
1215}1180}
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
1225static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1182static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1226 ZigType *type_entry)1183 ZigType *type_entry)
1227{1184{
...@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast...@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
14291386
1430static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,1387static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
1431 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1388 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,
1433 IrInstruction *new_stack, ResultLoc *result_loc)1390 IrInstruction *new_stack, ResultLoc *result_loc)
1434{1391{
1435 IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);1392 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...@@ -1440,22 +1397,24 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
1440 call_instruction->args = args;1397 call_instruction->args = args;
1441 call_instruction->arg_count = arg_count;1398 call_instruction->arg_count = arg_count;
1442 call_instruction->is_async = is_async;1399 call_instruction->is_async = is_async;
1443 call_instruction->async_allocator = async_allocator;
1444 call_instruction->new_stack = new_stack;1400 call_instruction->new_stack = new_stack;
1445 call_instruction->result_loc = result_loc;1401 call_instruction->result_loc = result_loc;
14461402
1447 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);1403 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
1448 for (size_t i = 0; i < arg_count; i += 1)1404 for (size_t i = 0; i < arg_count; i += 1)
1449 ir_ref_instruction(args[i], irb->current_basic_block);1405 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 }
1451 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);1410 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
14521411
1453 return &call_instruction->base;1412 return &call_instruction->base;
1454}1413}
14551414
1456static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,1415static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
1457 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1416 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,
1459 IrInstruction *result_loc, ZigType *return_type)1418 IrInstruction *result_loc, ZigType *return_type)
1460{1419{
1461 IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,1420 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...@@ -1467,18 +1426,16 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in
1467 call_instruction->args = args;1426 call_instruction->args = args;
1468 call_instruction->arg_count = arg_count;1427 call_instruction->arg_count = arg_count;
1469 call_instruction->is_async = is_async;1428 call_instruction->is_async = is_async;
1470 call_instruction->async_allocator = async_allocator;
1471 call_instruction->new_stack = new_stack;1429 call_instruction->new_stack = new_stack;
1472 call_instruction->result_loc = result_loc;1430 call_instruction->result_loc = result_loc;
14731431
1474 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);1432 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);
1475 for (size_t i = 0; i < arg_count; i += 1)1433 for (size_t i = 0; i < arg_count; i += 1)
1476 ir_ref_instruction(args[i], ira->new_irb.current_basic_block);1434 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);
1478 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);1435 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);
1479 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);1436 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;
1482}1439}
14831440
1484static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,1441static 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...@@ -1754,17 +1711,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
1754 return &instruction->base;1711 return &instruction->base;
1755}1712}
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,
1758 IrInstruction *payload_type)1715 IrInstruction *payload_type)
1759{1716{
1760 IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);1717 IrInstructionAnyFrameType *instruction = ir_build_instruction<IrInstructionAnyFrameType>(irb, scope, source_node);
1761 instruction->payload_type = payload_type;1718 instruction->payload_type = payload_type;
17621719
1763 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);1720 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
17641721
1765 return &instruction->base;1722 return &instruction->base;
1766}1723}
1767
1768static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1724static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1769 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)1725 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
1770{1726{
...@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo...@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo
2443}2399}
24442400
2445static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {2401static 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
2447 return &instruction->base;2431 return &instruction->base;
2448}2432}
24492433
...@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s
2546}2530}
25472531
2548static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,2532static 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)
2550{2534{
2551 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);2535 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);
2552 instruction->base_ptr = base_ptr;2536 instruction->base_ptr = base_ptr;
2553 instruction->resolve_err_set = resolve_err_set;2537 instruction->resolve_err_set = resolve_err_set;
2538 instruction->base_ptr_is_payload = base_ptr_is_payload;
25542539
2555 ir_ref_instruction(base_ptr, irb->current_basic_block);2540 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,...@@ -2596,13 +2581,12 @@ static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope,
25962581
2597static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,2582static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
2598 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,2583 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
2599 IrInstruction *async_allocator_type_value, bool is_var_args)2584 bool is_var_args)
2600{2585{
2601 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);2586 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
2602 instruction->param_types = param_types;2587 instruction->param_types = param_types;
2603 instruction->align_value = align_value;2588 instruction->align_value = align_value;
2604 instruction->return_type = return_type;2589 instruction->return_type = return_type;
2605 instruction->async_allocator_type_value = async_allocator_type_value;
2606 instruction->is_var_args = is_var_args;2590 instruction->is_var_args = is_var_args;
26072591
2608 assert(source_node->type == NodeTypeFnProto);2592 assert(source_node->type == NodeTypeFnProto);
...@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
2612 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);2596 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
2613 }2597 }
2614 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);2598 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);
2616 ir_ref_instruction(return_type, irb->current_basic_block);2599 ir_ref_instruction(return_type, irb->current_basic_block);
26172600
2618 return &instruction->base;2601 return &instruction->base;
...@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod...@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod
2994 return &instruction->base;2977 return &instruction->base;
2995}2978}
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
3009static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {2980static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3010 IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);2981 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...@@ -3056,149 +3027,6 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
3056 return &instruction->base;3027 return &instruction->base;
3057}3028}
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
3202static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,3030static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
3203 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,3031 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
3204 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)3032 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
...@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode...@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode
3238 return &instruction->base;3066 return &instruction->base;
3239}3067}
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
3263static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {3069static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3264 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);3070 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
3265 return &instruction->base;3071 return &instruction->base;
...@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s...@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
3276 return &instruction->base;3082 return &instruction->base;
3277}3083}
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
3303static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,3085static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
3304 IrInstruction *container, IrInstruction *name)3086 IrInstruction *container, IrInstruction *name)
3305{3087{
...@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode...@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode
3435 return &instruction->base;3217 return &instruction->base;
3436}3218}
34373219
3438static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,3220static IrInstructionAllocaGen *ir_build_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3439 uint32_t align, const char *name_hint)3221 uint32_t align, const char *name_hint)
3440{3222{
3441 IrInstructionAllocaGen *instruction = ir_create_instruction<IrInstructionAllocaGen>(&ira->new_irb,3223 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...@@ -3459,6 +3241,87 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s
3459 return &instruction->base;3241 return &instruction->base;
3460}3242}
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
3462static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {3325static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
3463 results[ReturnKindUnconditional] = 0;3326 results[ReturnKindUnconditional] = 0;
3464 results[ReturnKindError] = 0;3327 results[ReturnKindError] = 0;
...@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco...@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
3489 continue;3352 continue;
3490 case ScopeIdDeferExpr:3353 case ScopeIdDeferExpr:
3491 case ScopeIdCImport:3354 case ScopeIdCImport:
3492 case ScopeIdCoroPrelude:
3493 zig_unreachable();3355 zig_unreachable();
3494 }3356 }
3495 }3357 }
...@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
3545 continue;3407 continue;
3546 case ScopeIdDeferExpr:3408 case ScopeIdDeferExpr:
3547 case ScopeIdCImport:3409 case ScopeIdCImport:
3548 case ScopeIdCoroPrelude:
3549 zig_unreachable();3410 zig_unreachable();
3550 }3411 }
3551 }3412 }
...@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
3588 return nullptr;3449 return nullptr;
3589}3450}
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
3651static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {3452static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {
3652 assert(node->type == NodeTypeReturnExpr);3453 assert(node->type == NodeTypeReturnExpr);
36533454
...@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3689 return_value = ir_build_const_void(irb, scope, node);3490 return_value = ir_build_const_void(irb, scope, node);
3690 }3491 }
36913492
3493 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3494
3692 size_t defer_counts[2];3495 size_t defer_counts[2];
3693 ir_count_defers(irb, scope, outer_scope, defer_counts);3496 ir_count_defers(irb, scope, outer_scope, defer_counts);
3694 bool have_err_defers = defer_counts[ReturnKindError] > 0;3497 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3695 if (have_err_defers || irb->codegen->have_err_ret_tracing) {3498 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
3696 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");3499 // only generate unconditional defers
3697 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");3500 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3698 if (!have_err_defers) {3501 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3699 ir_gen_defers_for_block(irb, scope, outer_scope, false);3502 result_loc_ret->base.source_instruction = result;
3700 }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,3507 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3703 return_value);3508 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
3704 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false);
37053509
3706 bool should_inline = ir_should_inline(irb->exec, scope);3510 if (!have_err_defers) {
3707 IrInstruction *is_comptime;3511 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3708 if (should_inline) {3512 }
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 }
37133513
3714 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));3514 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
3715 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
37163515
3717 ir_set_cursor_at_end_and_append_block(irb, err_block);3516 IrInstruction *is_comptime;
3718 if (have_err_defers) {3517 if (should_inline) {
3719 ir_gen_defers_for_block(irb, scope, outer_scope, true);3518 is_comptime = ir_build_const_bool(irb, scope, node, should_inline);
3720 }3519 } else {
3721 if (irb->codegen->have_err_ret_tracing && !should_inline) {3520 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3722 ir_build_save_err_ret_addr(irb, scope, node);3521 }
3723 }
3724 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
37253522
3726 ir_set_cursor_at_end_and_append_block(irb, ok_block);3523 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3727 if (have_err_defers) {3524 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
3728 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3729 }
3730 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
37313525
3732 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);3526 ir_set_cursor_at_end_and_append_block(irb, err_block);
3733 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);3527 if (have_err_defers) {
3734 result_loc_ret->base.source_instruction = result;3528 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3735 return result;3529 }
3736 } else {3530 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3737 // generate unconditional defers3531 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) {
3738 ir_gen_defers_for_block(irb, scope, outer_scope, false);3537 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;
3742 }3538 }
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;
3743 }3545 }
3744 case ReturnKindError:3546 case ReturnKindError:
3745 {3547 {
...@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3747 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);3549 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
3748 if (err_union_ptr == irb->codegen->invalid_instruction)3550 if (err_union_ptr == irb->codegen->invalid_instruction)
3749 return irb->codegen->invalid_instruction;3551 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
3752 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");3554 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
3753 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");3555 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,...@@ -3761,19 +3563,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3761 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));3563 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
37623564
3763 ir_set_cursor_at_end_and_append_block(irb, return_block);3565 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);
3764 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {3575 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
3773 if (irb->codegen->have_err_ret_tracing && !should_inline) {3576 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3774 ir_build_save_err_ret_addr(irb, scope, node);3577 ir_build_save_err_ret_addr(irb, scope, node);
3775 }3578 }
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);
3777 result_loc_ret->base.source_instruction = ret_inst;3581 result_loc_ret->base.source_instruction = ret_inst;
3778 }3582 }
37793583
...@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3971 incoming_values.append(else_expr_result);3775 incoming_values.append(else_expr_result);
3972 }3776 }
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) {
3975 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);3780 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) {
3976 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));3785 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
3977 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);3786 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
3978 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,3787 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
3979 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);3788 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);
3981 } else {3790 } else {
3982 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3983 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));3791 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);
3985 }3793 }
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));
3986}3803}
39873804
3988static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {3805static 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...@@ -4561,8 +4378,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4561 return irb->codegen->invalid_instruction;4378 return irb->codegen->invalid_instruction;
4562 }4379 }
45634380
4564 bool is_async = exec_is_async(irb->exec);
4565
4566 switch (builtin_fn->id) {4381 switch (builtin_fn->id) {
4567 case BuiltinFnIdInvalid:4382 case BuiltinFnIdInvalid:
4568 zig_unreachable();4383 zig_unreachable();
...@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5185 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);5000 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);
5186 case BuiltinFnIdFrameAddress:5001 case BuiltinFnIdFrameAddress:
5187 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);5002 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);
5188 case BuiltinFnIdHandle:5003 case BuiltinFnIdFrameHandle:
5189 if (!irb->exec->fn_entry) {5004 if (!irb->exec->fn_entry) {
5190 add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));5005 add_node_error(irb->codegen, node, buf_sprintf("@frame() 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"));
5195 return irb->codegen->invalid_instruction;5006 return irb->codegen->invalid_instruction;
5196 }5007 }
5197 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);5008 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 }
5198 case BuiltinFnIdAlignOf:5027 case BuiltinFnIdAlignOf:
5199 {5028 {
5200 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);5029 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...@@ -5395,13 +5224,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5395 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;5224 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
53965225
5397 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,5226 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);
5399 return ir_lval_wrap(irb, scope, call, lval, result_loc);5228 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5400 }5229 }
5401 case BuiltinFnIdNewStackCall:5230 case BuiltinFnIdNewStackCall:
5402 {5231 {
5403 if (node->data.fn_call_expr.params.length == 0) {5232 if (node->data.fn_call_expr.params.length < 2) {
5404 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));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));
5405 return irb->codegen->invalid_instruction;5236 return irb->codegen->invalid_instruction;
5406 }5237 }
54075238
...@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5426 }5257 }
54275258
5428 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,5259 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);
5430 return ir_lval_wrap(irb, scope, call, lval, result_loc);5305 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5431 }5306 }
5432 case BuiltinFnIdTypeId:5307 case BuiltinFnIdTypeId:
...@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node...@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
5731 }5606 }
57325607
5733 bool is_async = node->data.fn_call_expr.is_async;5608 bool is_async = node->data.fn_call_expr.is_async;
5734 IrInstruction *async_allocator = nullptr;5609 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5735 if (is_async) {5610 FnInlineAuto, is_async, nullptr, result_loc);
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);
5745 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);5611 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);
5746}5612}
57475613
...@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
6254 LValPtr, nullptr);6120 LValPtr, nullptr);
6255 if (err_val_ptr == irb->codegen->invalid_instruction)6121 if (err_val_ptr == irb->codegen->invalid_instruction)
6256 return err_val_ptr;6122 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);
6258 IrBasicBlock *after_cond_block = irb->current_basic_block;6125 IrBasicBlock *after_cond_block = irb->current_basic_block;
6259 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));6126 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
6260 IrInstruction *cond_br_inst;6127 IrInstruction *cond_br_inst;
...@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n...@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
6762 }6629 }
6763}6630}
67646631
6765static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {6632static IrInstruction *ir_gen_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6766 assert(node->type == NodeTypePromiseType);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;
6769 IrInstruction *payload_type_value = nullptr;6636 IrInstruction *payload_type_value = nullptr;
67706637
6771 if (payload_type_node != nullptr) {6638 if (payload_type_node != nullptr) {
...@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode...@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
67756642
6776 }6643 }
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);
6779}6646}
67806647
6781static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {6648static 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 *...@@ -7070,7 +6937,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
7070 return err_val_ptr;6937 return err_val_ptr;
70716938
7072 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);6939 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
7075 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");6942 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
7076 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");6943 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...@@ -7686,7 +7553,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
7686 if (err_union_ptr == irb->codegen->invalid_instruction)7553 if (err_union_ptr == irb->codegen->invalid_instruction)
7687 return irb->codegen->invalid_instruction;7554 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
7691 IrInstruction *is_comptime;7558 IrInstruction *is_comptime;
7692 if (ir_should_inline(irb->exec, parent_scope)) {7559 if (ir_should_inline(irb->exec, parent_scope)) {
...@@ -7967,352 +7834,58 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -7967,352 +7834,58 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
7967 IrInstruction *return_type;7834 IrInstruction *return_type;
7968 if (node->data.fn_proto.return_var_token == nullptr) {7835 if (node->data.fn_proto.return_var_token == nullptr) {
7969 if (node->data.fn_proto.return_type == nullptr) {7836 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);7837 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
7971 } else {7838 } else {
7972 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);7839 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
7973 if (return_type == irb->codegen->invalid_instruction)7840 if (return_type == irb->codegen->invalid_instruction)
7974 return irb->codegen->invalid_instruction;7841 return irb->codegen->invalid_instruction;
7975 }7842 }
7976 } else {7843 } else {
7977 add_node_error(irb->codegen, node,7844 add_node_error(irb->codegen, node,
7978 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));7845 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)
8071 return irb->codegen->invalid_instruction;7846 return irb->codegen->invalid_instruction;
7847 //return_type = nullptr;
7848 }
80727849
8073 return ir_gen_cancel_target(irb, scope, node, target_inst, false, true);7850 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
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);
8124}7851}
81257852
8126static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {7853static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
8127 assert(node->type == NodeTypeResume);7854 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);
8130 if (target_inst == irb->codegen->invalid_instruction)7857 if (target_inst == irb->codegen->invalid_instruction)
8131 return irb->codegen->invalid_instruction;7858 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);
8134}7861}
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{
8137 assert(node->type == NodeTypeAwaitExpr);7866 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
8143 ZigFn *fn_entry = exec_fn_entry(irb->exec);7868 ZigFn *fn_entry = exec_fn_entry(irb->exec);
8144 if (!fn_entry) {7869 if (!fn_entry) {
8145 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));7870 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
8146 return irb->codegen->invalid_instruction;7871 return irb->codegen->invalid_instruction;
8147 }7872 }
8148 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {7873 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
8149 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));7874 if (existing_suspend_scope) {
8150 return irb->codegen->invalid_instruction;7875 if (!existing_suspend_scope->reported_err) {
8151 }7876 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block"));
81527877 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
8153 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);7878 existing_suspend_scope->reported_err = true;
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;
8158 }7879 }
8159 return irb->codegen->invalid_instruction;7880 return irb->codegen->invalid_instruction;
8160 }7881 }
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);7887 IrInstruction *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc);
8165 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);7888 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
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);
8316}7889}
83177890
8318static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {7891static 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...@@ -8323,20 +7896,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
8323 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));7896 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
8324 return irb->codegen->invalid_instruction;7897 return irb->codegen->invalid_instruction;
8325 }7898 }
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 }
8340 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);7899 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
8341 if (existing_suspend_scope) {7900 if (existing_suspend_scope) {
8342 if (!existing_suspend_scope->reported_err) {7901 if (!existing_suspend_scope->reported_err) {
...@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
8347 return irb->codegen->invalid_instruction;7906 return irb->codegen->invalid_instruction;
8348 }7907 }
83497908
8350 Scope *outer_scope = irb->exec->begin_scope;7909 IrInstructionSuspendBegin *begin = ir_build_suspend_begin(irb, parent_scope, node);
83517910 if (node->data.suspend.block != nullptr) {
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;
8404 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);7911 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
8405 suspend_scope->resume_block = resume_block;7912 Scope *child_scope = &suspend_scope->base;
8406 child_scope = &suspend_scope->base;7913 IrInstruction *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
8407 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);7914 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
8408 ir_gen_node(irb, node->data.suspend.block, child_scope);7915 }
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));
84327916
8433 ir_set_cursor_at_end_and_append_block(irb, resume_block);7917 return ir_build_suspend_finish(irb, parent_scope, node, begin);
8434 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
8435}7918}
84367919
8437static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,7920static 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...@@ -8523,8 +8006,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
8523 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);8006 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);
8524 case NodeTypePointerType:8007 case NodeTypePointerType:
8525 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);8008 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);
8526 case NodeTypePromiseType:8009 case NodeTypeAnyFrameType:
8527 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc);8010 return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc);
8528 case NodeTypeStringLiteral:8011 case NodeTypeStringLiteral:
8529 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);8012 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);
8530 case NodeTypeUndefinedLiteral:8013 case NodeTypeUndefinedLiteral:
...@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
8561 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);8044 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);
8562 case NodeTypeErrorSetDecl:8045 case NodeTypeErrorSetDecl:
8563 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc);8046 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);
8566 case NodeTypeResume:8047 case NodeTypeResume:
8567 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);8048 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);
8568 case NodeTypeAwaitExpr:8049 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);
8570 case NodeTypeSuspend:8051 case NodeTypeSuspend:
8571 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);8052 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);
8572 case NodeTypeEnumLiteral:8053 case NodeTypeEnumLiteral:
...@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
86268107
8627 irb->codegen = codegen;8108 irb->codegen = codegen;
8628 irb->exec = ir_executable;8109 irb->exec = ir_executable;
8110 irb->main_block_node = node;
86298111
8630 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");8112 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");
8631 ir_set_cursor_at_end_and_append_block(irb, entry_block);8113 ir_set_cursor_at_end_and_append_block(irb, entry_block);
8632 // Entry block gets a reference because we enter it to begin.8114 // Entry block gets a reference because we enter it to begin.
8633 ir_ref_bb(irb->current_basic_block);8115 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
8739 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);8117 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
8740 assert(result);8118 assert(result);
8741 if (irb->exec->invalid)8119 if (irb->exec->invalid)
8742 return false;8120 return false;
87438121
8744 if (!instr_is_unreachable(result)) {8122 if (!instr_is_unreachable(result)) {
8123 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));
8745 // no need for save_err_ret_addr because this cannot return error8124 // no need for save_err_ret_addr because this cannot return error
8746 ir_gen_async_return(irb, scope, result->source_node, result, true);8125 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
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);
8858 }8126 }
88598127
8860 return true;8128 return true;
...@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {...@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
8871 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);8139 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);
8872}8140}
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) {
8875 if (!exec || !exec->source_node || limit < 0) return;8143 if (!exec || !exec->source_node || limit < 0) return;
8876 add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));8144 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);
8879}8153}
88808154
8881static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {8155static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
8882 invalidate_exec(exec);8156 invalidate_exec(exec);
8883 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);8157 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
8884 if (exec->parent_exec) {8158 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);
8886 }8160 }
8887 return err_msg;8161 return err_msg;
8888}8162}
...@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec...@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec
8946 IrInstruction *instruction = bb->instruction_list.at(i);8220 IrInstruction *instruction = bb->instruction_list.at(i);
8947 if (instruction->id == IrInstructionIdReturn) {8221 if (instruction->id == IrInstructionIdReturn) {
8948 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;8222 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;
8949 IrInstruction *value = ret_inst->value;8223 IrInstruction *operand = ret_inst->operand;
8950 if (value->value.special == ConstValSpecialRuntime) {8224 if (operand->value.special == ConstValSpecialRuntime) {
8951 exec_add_error_node(codegen, exec, value->source_node,8225 exec_add_error_node(codegen, exec, operand->source_node,
8952 buf_sprintf("unable to evaluate constant expression"));8226 buf_sprintf("unable to evaluate constant expression"));
8953 return &codegen->invalid_instruction->value;8227 return &codegen->invalid_instruction->value;
8954 }8228 }
8955 return &value->value;8229 return &operand->value;
8956 } else if (ir_has_side_effects(instruction)) {8230 } else if (ir_has_side_effects(instruction)) {
8957 if (instr_is_comptime(instruction)) {8231 if (instr_is_comptime(instruction)) {
8958 switch (instruction->id) {8232 switch (instruction->id) {
...@@ -10203,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -10203,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
10203 return result;9477 return result;
10204 }9478 }
102059479
10206 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
10207 actual_type->id == ZigTypeIdPromise)
10208 {
10209 return result;
10210 }
10211
10212 // fn9480 // fn
10213 if (wanted_type->id == ZigTypeIdFn &&9481 if (wanted_type->id == ZigTypeIdFn &&
10214 actual_type->id == ZigTypeIdFn)9482 actual_type->id == ZigTypeIdFn)
...@@ -10243,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -10243,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
10243 return result;9511 return result;
10244 }9512 }
10245 }9513 }
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 }
10260 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {9514 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
10261 result.id = ConstCastResultIdFnArgCount;9515 result.id = ConstCastResultIdFnArgCount;
10262 return result;9516 return result;
...@@ -10561,6 +9815,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT...@@ -10561,6 +9815,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
105619815
10562 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;9816 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
10563 ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type;9817 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
10565 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {9821 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
10566 return ira->codegen->builtin_types.entry_invalid;9822 return ira->codegen->builtin_types.entry_invalid;
...@@ -11206,7 +10462,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,...@@ -11206,7 +10462,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,
11206}10462}
1120710463
11208static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) {10464static 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);
11210 ira->instruction_index = 0;10466 ira->instruction_index = 0;
11211 ira->old_irb.current_basic_block = old_bb;10467 ira->old_irb.current_basic_block = old_bb;
11212 ira->const_predecessor_bb = const_predecessor_bb;10468 ira->const_predecessor_bb = const_predecessor_bb;
...@@ -11729,6 +10985,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou...@@ -11729,6 +10985,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
11729 return result;10985 return result;
11730}10986}
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
11732static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,11015static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
11733 ZigType *wanted_type, ResultLoc *result_loc)11016 ZigType *wanted_type, ResultLoc *result_loc)
11734{11017{
...@@ -12576,12 +11859,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou...@@ -12576,12 +11859,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou
12576static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {11859static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {
12577 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;11860 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;
12578 if (ty->id == ZigTypeIdFn) return true;11861 if (ty->id == ZigTypeIdFn) return true;
12579 if (ty->id == ZigTypeIdPromise) return true;
12580 if (ty->id == ZigTypeIdOptional) {11862 if (ty->id == ZigTypeIdOptional) {
12581 ZigType *ptr_ty = ty->data.maybe.child_type;11863 ZigType *ptr_ty = ty->data.maybe.child_type;
12582 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;11864 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;
12583 if (ptr_ty->id == ZigTypeIdFn) return true;11865 if (ptr_ty->id == ZigTypeIdFn) return true;
12584 if (ptr_ty->id == ZigTypeIdPromise) return true;
12585 }11866 }
12586 return false;11867 return false;
12587}11868}
...@@ -12829,6 +12110,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -12829,6 +12110,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
12829 }12110 }
12830 }12111 }
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
12833 // cast from null literal to maybe type12137 // cast from null literal to maybe type
12834 if (wanted_type->id == ZigTypeIdOptional &&12138 if (wanted_type->id == ZigTypeIdOptional &&
...@@ -13333,11 +12637,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze...@@ -13333,11 +12637,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
13333}12637}
1333412638
13335static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {12639static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {
13336 IrInstruction *value = instruction->value->child;12640 IrInstruction *operand = instruction->operand->child;
13337 if (type_is_invalid(value->value.type))12641 if (type_is_invalid(operand->value.type))
13338 return ir_unreach_error(ira);12642 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)) {
13341 // result location mechanism took care of it.12645 // result location mechanism took care of it.
13342 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,12646 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
13343 instruction->base.source_node, nullptr);12647 instruction->base.source_node, nullptr);
...@@ -13345,8 +12649,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio...@@ -13345,8 +12649,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
13345 return ir_finish_anal(ira, result);12649 return ir_finish_anal(ira, result);
13346 }12650 }
1334712651
13348 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);12652 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type);
13349 if (type_is_invalid(casted_value->value.type)) {12653 if (type_is_invalid(casted_operand->value.type)) {
13350 AstNode *source_node = ira->explicit_return_type_source_node;12654 AstNode *source_node = ira->explicit_return_type_source_node;
13351 if (source_node != nullptr) {12655 if (source_node != nullptr) {
13352 ErrorMsg *msg = ira->codegen->errors.last();12656 ErrorMsg *msg = ira->codegen->errors.last();
...@@ -13356,15 +12660,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio...@@ -13356,15 +12660,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
13356 return ir_unreach_error(ira);12660 return ir_unreach_error(ira);
13357 }12661 }
1335812662
13359 if (casted_value->value.special == ConstValSpecialRuntime &&12663 if (casted_operand->value.special == ConstValSpecialRuntime &&
13360 casted_value->value.type->id == ZigTypeIdPointer &&12664 casted_operand->value.type->id == ZigTypeIdPointer &&
13361 casted_value->value.data.rh_ptr == RuntimeHintPtrStack)12665 casted_operand->value.data.rh_ptr == RuntimeHintPtrStack)
13362 {12666 {
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"));
13364 return ir_unreach_error(ira);12668 return ir_unreach_error(ira);
13365 }12669 }
12670
13366 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,12671 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);
13368 result->value.type = ira->codegen->builtin_types.entry_unreachable;12673 result->value.type = ira->codegen->builtin_types.entry_unreachable;
13369 return ir_finish_anal(ira, result);12674 return ir_finish_anal(ira, result);
13370}12675}
...@@ -13658,9 +12963,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13658,9 +12963,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13658 case ZigTypeIdOpaque:12963 case ZigTypeIdOpaque:
13659 case ZigTypeIdBoundFn:12964 case ZigTypeIdBoundFn:
13660 case ZigTypeIdArgTuple:12965 case ZigTypeIdArgTuple:
13661 case ZigTypeIdPromise:
13662 case ZigTypeIdEnum:12966 case ZigTypeIdEnum:
13663 case ZigTypeIdEnumLiteral:12967 case ZigTypeIdEnumLiteral:
12968 case ZigTypeIdAnyFrame:
13664 operator_allowed = is_equality_cmp;12969 operator_allowed = is_equality_cmp;
13665 break;12970 break;
1366612971
...@@ -13675,6 +12980,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13675,6 +12980,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13675 case ZigTypeIdNull:12980 case ZigTypeIdNull:
13676 case ZigTypeIdErrorUnion:12981 case ZigTypeIdErrorUnion:
13677 case ZigTypeIdUnion:12982 case ZigTypeIdUnion:
12983 case ZigTypeIdFnFrame:
13678 operator_allowed = false;12984 operator_allowed = false;
13679 break;12985 break;
13680 case ZigTypeIdOptional:12986 case ZigTypeIdOptional:
...@@ -15039,7 +14345,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -15039,7 +14345,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
15039 case ZigTypeIdBoundFn:14345 case ZigTypeIdBoundFn:
15040 case ZigTypeIdArgTuple:14346 case ZigTypeIdArgTuple:
15041 case ZigTypeIdOpaque:14347 case ZigTypeIdOpaque:
15042 case ZigTypeIdPromise:14348 case ZigTypeIdFnFrame:
14349 case ZigTypeIdAnyFrame:
15043 ir_add_error(ira, target,14350 ir_add_error(ira, target,
15044 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));14351 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));
15045 break;14352 break;
...@@ -15063,8 +14370,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -15063,8 +14370,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
15063 case ZigTypeIdBoundFn:14370 case ZigTypeIdBoundFn:
15064 case ZigTypeIdArgTuple:14371 case ZigTypeIdArgTuple:
15065 case ZigTypeIdOpaque:14372 case ZigTypeIdOpaque:
15066 case ZigTypeIdPromise:
15067 case ZigTypeIdEnumLiteral:14373 case ZigTypeIdEnumLiteral:
14374 case ZigTypeIdFnFrame:
14375 case ZigTypeIdAnyFrame:
15068 ir_add_error(ira, target,14376 ir_add_error(ira, target,
15069 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));14377 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));
15070 break;14378 break;
...@@ -15091,8 +14399,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {...@@ -15091,8 +14399,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
15091static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,14399static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
15092 IrInstructionErrorReturnTrace *instruction)14400 IrInstructionErrorReturnTrace *instruction)
15093{14401{
14402 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false);
15094 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {14403 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
15095 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
15096 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);14404 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
15097 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {14405 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
15098 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);14406 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);
...@@ -15110,7 +14418,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,...@@ -15110,7 +14418,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
15110 assert(ira->codegen->have_err_ret_tracing);14418 assert(ira->codegen->have_err_ret_tracing);
15111 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,14419 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
15112 instruction->base.source_node, instruction->optional);14420 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;
15114 return new_instruction;14422 return new_instruction;
15115 }14423 }
15116}14424}
...@@ -15142,42 +14450,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,...@@ -15142,42 +14450,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
15142 return ir_const_type(ira, &instruction->base, result_type);14450 return ir_const_type(ira, &instruction->base, result_type);
15143}14451}
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
15181static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,14453static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,
15182 uint32_t align, const char *name_hint, bool force_comptime)14454 uint32_t align, const char *name_hint, bool force_comptime)
15183{14455{
...@@ -15186,7 +14458,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in...@@ -15186,7 +14458,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in
15186 ConstExprValue *pointee = create_const_vals(1);14458 ConstExprValue *pointee = create_const_vals(1);
15187 pointee->special = ConstValSpecialUndef;14459 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);
15190 result->base.value.special = ConstValSpecialStatic;14462 result->base.value.special = ConstValSpecialStatic;
15191 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;14463 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
15192 result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer;14464 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...@@ -15283,7 +14555,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
15283 return nullptr;14555 return nullptr;
15284 }14556 }
15285 // need to return a result location and don't have one. use a stack allocation14557 // 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, "");
15287 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))14559 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))
15288 return ira->codegen->invalid_instruction;14560 return ira->codegen->invalid_instruction;
15289 alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false,14561 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...@@ -15353,8 +14625,12 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
15353 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {14625 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {
15354 return ira->codegen->invalid_instruction;14626 return ira->codegen->invalid_instruction;
15355 }14627 }
15356 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type))14628 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) {
15357 return nullptr;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
15359 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);14635 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);
15360 result_loc->written = true;14636 result_loc->written = true;
...@@ -15616,48 +14892,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst...@@ -15616,48 +14892,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
1561614892
15617static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,14893static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
15618 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,14894 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
15619 IrInstruction *async_allocator_inst)14895 IrInstruction *casted_new_stack)
15620{14896{
15621 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);14897 if (casted_new_stack != nullptr) {
15622 ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base);14898 // this is an @asyncCall
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);
1563114899
15632 ZigType *realloc_fn_type = ptr_to_realloc_fn_type->data.pointer.child_type;14900 if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
15633 if (realloc_fn_type->id != ZigTypeIdFn) {14901 ir_add_error(ira, fn_ref,
15634 ir_add_error(ira, &call_instruction->base,14902 buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
15635 buf_sprintf("expected reallocation function, found '%s'", buf_ptr(&realloc_fn_type->name)));14903 return ira->codegen->invalid_instruction;
15636 return ira->codegen->invalid_instruction;14904 }
15637 }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;14912 IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
15640 if (realloc_fn_return_type->id != ZigTypeIdErrorUnion) {14913 arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type);
15641 ir_add_error(ira, fn_ref,14914 return &call_gen->base;
15642 buf_sprintf("expected allocation function to return error union, but it returns '%s'", buf_ptr(&realloc_fn_return_type->name)));14915 } else if (fn_entry == nullptr) {
14916 ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
15643 return ira->codegen->invalid_instruction;14917 return ira->codegen->invalid_instruction;
15644 }14918 }
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(),14920 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry);
15651 async_return_type, nullptr, true, true, false);14921 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
15652 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(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))) {
15653 return result_loc;14924 return result_loc;
15654 }14925 }
1565514926 result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
15656 return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,14927 if (type_is_invalid(result_loc->value.type))
15657 casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc,14928 return ira->codegen->invalid_instruction;
15658 async_return_type);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;
15659}14931}
15660
15661static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,14932static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
15662 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)14933 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
15663{14934{
...@@ -16004,20 +15275,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16004,20 +15275,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16004 }15275 }
16005 return ira->codegen->invalid_instruction;15276 return ira->codegen->invalid_instruction;
16006 }15277 }
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
16023 if (fn_type_id->is_var_args) {15280 if (fn_type_id->is_var_args) {
...@@ -16354,33 +15611,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16354,33 +15611,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16354 break;15611 break;
16355 }15612 }
16356 }15613 }
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
16385 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);15615 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
16386 if (existing_entry) {15616 if (existing_entry) {
...@@ -16423,17 +15653,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16423,17 +15653,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16423 size_t impl_param_count = impl_fn_type_id->param_count;15653 size_t impl_param_count = impl_fn_type_id->param_count;
16424 if (call_instruction->is_async) {15654 if (call_instruction->is_async) {
16425 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,15655 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);
16427 return ir_finish_anal(ira, result);15657 return ir_finish_anal(ira, result);
16428 }15658 }
1642915659
16430 assert(async_allocator_inst == nullptr);15660 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
16431 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,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,
16432 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,15666 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,
16434 impl_fn_type_id->return_type);15668 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);
16437 }15673 }
1643815674
16439 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);15675 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...@@ -16475,20 +15711,56 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16475 IrInstruction *old_arg = call_instruction->args[call_i]->child;15711 IrInstruction *old_arg = call_instruction->args[call_i]->child;
16476 if (type_is_invalid(old_arg->value.type))15712 if (type_is_invalid(old_arg->value.type))
16477 return ira->codegen->invalid_instruction;15713 return ira->codegen->invalid_instruction;
16478 IrInstruction *casted_arg;15714
16479 if (next_arg_index < src_param_count) {15715 if (old_arg->value.type->id == ZigTypeIdArgTuple) {
16480 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;15716 for (size_t arg_tuple_i = old_arg->value.data.x_arg_tuple.start_index;
16481 if (type_is_invalid(param_type))15717 arg_tuple_i < old_arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
16482 return ira->codegen->invalid_instruction;15718 {
16483 casted_arg = ir_implicit_cast(ira, old_arg, param_type);15719 ZigVar *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
16484 if (type_is_invalid(casted_arg->value.type))15720 if (arg_var == nullptr) {
16485 return ira->codegen->invalid_instruction;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 }
16486 } else {15748 } else {
16487 casted_arg = old_arg;15749 IrInstruction *casted_arg;
16488 }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;15761 casted_args[next_arg_index] = casted_arg;
16491 next_arg_index += 1;15762 next_arg_index += 1;
15763 }
16492 }15764 }
1649315765
16494 assert(next_arg_index == call_param_count);15766 assert(next_arg_index == call_param_count);
...@@ -16497,32 +15769,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16497,32 +15769,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16497 if (type_is_invalid(return_type))15769 if (type_is_invalid(return_type))
16498 return ira->codegen->invalid_instruction;15770 return ira->codegen->invalid_instruction;
1649915771
16500 if (call_instruction->is_async) {15772 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
16501 IrInstruction *uncasted_async_allocator_inst;15773 ir_add_error(ira, &call_instruction->base,
16502 if (call_instruction->async_allocator == nullptr) {15774 buf_sprintf("no-inline call of inline function"));
16503 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,15775 return ira->codegen->invalid_instruction;
16504 ImplicitAllocatorIdLocalVar);15776 }
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;
1651615777
15778 if (call_instruction->is_async) {
16517 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,15779 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);
16519 return ir_finish_anal(ira, result);15781 return ir_finish_anal(ira, result);
16520 }15782 }
1652115783
16522 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {15784 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
16523 ir_add_error(ira, &call_instruction->base,15785 parent_fn_entry->inferred_async_node = fn_ref->source_node;
16524 buf_sprintf("no-inline call of inline function"));15786 parent_fn_entry->inferred_async_fn = fn_entry;
16525 return ira->codegen->invalid_instruction;
16526 }15787 }
1652715788
16528 IrInstruction *result_loc;15789 IrInstruction *result_loc;
...@@ -16536,10 +15797,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16536,10 +15797,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16536 result_loc = nullptr;15797 result_loc = nullptr;
16537 }15798 }
1653815799
16539 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,15800 IrInstructionCallGen *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,15801 call_param_count, casted_args, fn_inline, false, casted_new_stack,
16541 result_loc, return_type);15802 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);
16543}15805}
1654415806
16545static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {15807static 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...@@ -16684,7 +15946,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
16684 zig_unreachable();15946 zig_unreachable();
16685}15947}
1668615948
16687static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {15949static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
16688 Error err;15950 Error err;
16689 IrInstruction *value = un_op_instruction->value->child;15951 IrInstruction *value = un_op_instruction->value->child;
16690 ZigType *type_entry = ir_resolve_type(ira, value);15952 ZigType *type_entry = ir_resolve_type(ira, value);
...@@ -16718,8 +15980,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_...@@ -16718,8 +15980,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
16718 case ZigTypeIdFn:15980 case ZigTypeIdFn:
16719 case ZigTypeIdBoundFn:15981 case ZigTypeIdBoundFn:
16720 case ZigTypeIdArgTuple:15982 case ZigTypeIdArgTuple:
16721 case ZigTypeIdPromise:15983 case ZigTypeIdFnFrame:
15984 case ZigTypeIdAnyFrame:
16722 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));15985 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));
15986
16723 case ZigTypeIdUnreachable:15987 case ZigTypeIdUnreachable:
16724 case ZigTypeIdOpaque:15988 case ZigTypeIdOpaque:
16725 ir_add_error_node(ira, un_op_instruction->base.source_node,15989 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...@@ -16883,7 +16147,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
16883 return result;16147 return result;
16884 }16148 }
16885 case IrUnOpOptional:16149 case IrUnOpOptional:
16886 return ir_analyze_maybe(ira, instruction);16150 return ir_analyze_optional_type(ira, instruction);
16887 }16151 }
16888 zig_unreachable();16152 zig_unreachable();
16889}16153}
...@@ -18443,6 +17707,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,...@@ -18443,6 +17707,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
18443 return ir_const_void(ira, &instruction->base);17707 return ir_const_void(ira, &instruction->base);
18444}17708}
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
18446static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,17724static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
18447 IrInstructionSliceType *slice_type_instruction)17725 IrInstructionSliceType *slice_type_instruction)
18448{17726{
...@@ -18490,8 +17768,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -18490,8 +17768,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
18490 case ZigTypeIdUnion:17768 case ZigTypeIdUnion:
18491 case ZigTypeIdFn:17769 case ZigTypeIdFn:
18492 case ZigTypeIdBoundFn:17770 case ZigTypeIdBoundFn:
18493 case ZigTypeIdPromise:
18494 case ZigTypeIdVector:17771 case ZigTypeIdVector:
17772 case ZigTypeIdFnFrame:
17773 case ZigTypeIdAnyFrame:
18495 {17774 {
18496 ResolveStatus needed_status = (align_bytes == 0) ?17775 ResolveStatus needed_status = (align_bytes == 0) ?
18497 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;17776 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
...@@ -18605,8 +17884,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -18605,8 +17884,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
18605 case ZigTypeIdUnion:17884 case ZigTypeIdUnion:
18606 case ZigTypeIdFn:17885 case ZigTypeIdFn:
18607 case ZigTypeIdBoundFn:17886 case ZigTypeIdBoundFn:
18608 case ZigTypeIdPromise:
18609 case ZigTypeIdVector:17887 case ZigTypeIdVector:
17888 case ZigTypeIdFnFrame:
17889 case ZigTypeIdAnyFrame:
18610 {17890 {
18611 if ((err = ensure_complete_type(ira->codegen, child_type)))17891 if ((err = ensure_complete_type(ira->codegen, child_type)))
18612 return ira->codegen->invalid_instruction;17892 return ira->codegen->invalid_instruction;
...@@ -18617,22 +17897,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -18617,22 +17897,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
18617 zig_unreachable();17897 zig_unreachable();
18618}17898}
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
18636static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,17900static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
18637 IrInstructionSizeOf *size_of_instruction)17901 IrInstructionSizeOf *size_of_instruction)
18638{17902{
...@@ -18672,8 +17936,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -18672,8 +17936,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
18672 case ZigTypeIdEnum:17936 case ZigTypeIdEnum:
18673 case ZigTypeIdUnion:17937 case ZigTypeIdUnion:
18674 case ZigTypeIdFn:17938 case ZigTypeIdFn:
18675 case ZigTypeIdPromise:
18676 case ZigTypeIdVector:17939 case ZigTypeIdVector:
17940 case ZigTypeIdFnFrame:
17941 case ZigTypeIdAnyFrame:
18677 {17942 {
18678 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);17943 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
18679 return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);17944 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,...@@ -19159,7 +18424,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
19159 case ZigTypeIdComptimeInt:18424 case ZigTypeIdComptimeInt:
19160 case ZigTypeIdEnumLiteral:18425 case ZigTypeIdEnumLiteral:
19161 case ZigTypeIdPointer:18426 case ZigTypeIdPointer:
19162 case ZigTypeIdPromise:
19163 case ZigTypeIdFn:18427 case ZigTypeIdFn:
19164 case ZigTypeIdErrorSet: {18428 case ZigTypeIdErrorSet: {
19165 if (pointee_val) {18429 if (pointee_val) {
...@@ -19238,6 +18502,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -19238,6 +18502,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
19238 case ZigTypeIdArgTuple:18502 case ZigTypeIdArgTuple:
19239 case ZigTypeIdOpaque:18503 case ZigTypeIdOpaque:
19240 case ZigTypeIdVector:18504 case ZigTypeIdVector:
18505 case ZigTypeIdFnFrame:
18506 case ZigTypeIdAnyFrame:
19241 ir_add_error(ira, &switch_target_instruction->base,18507 ir_add_error(ira, &switch_target_instruction->base,
19242 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));18508 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
19243 return ira->codegen->invalid_instruction;18509 return ira->codegen->invalid_instruction;
...@@ -20672,32 +19938,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -20672,32 +19938,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2067219938
20673 break;19939 break;
20674 }19940 }
20675 case ZigTypeIdPromise:19941 case ZigTypeIdAnyFrame: {
20676 {19942 result = create_const_vals(1);
20677 result = create_const_vals(1);19943 result->special = ConstValSpecialStatic;
20678 result->special = ConstValSpecialStatic;19944 result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr);
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);
2068819945
20689 if (type_entry->data.promise.result_type == nullptr)19946 ConstExprValue *fields = create_const_vals(1);
20690 fields[0].data.x_optional = nullptr;19947 result->data.x_struct.fields = fields;
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 }
2069819948
20699 break;19949 // child: ?type
20700 }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 }
20701 case ZigTypeIdEnum:19957 case ZigTypeIdEnum:
20702 {19958 {
20703 result = create_const_vals(1);19959 result = create_const_vals(1);
...@@ -21007,7 +20263,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -21007,7 +20263,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21007 result->special = ConstValSpecialStatic;20263 result->special = ConstValSpecialStatic;
21008 result->type = ir_type_info_get_type(ira, "Fn", nullptr);20264 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);
21011 result->data.x_struct.fields = fields;20267 result->data.x_struct.fields = fields;
2101220268
21013 // calling_convention: TypeInfo.CallingConvention20269 // calling_convention: TypeInfo.CallingConvention
...@@ -21038,20 +20294,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -21038,20 +20294,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21038 return_type->special = ConstValSpecialStatic;20294 return_type->special = ConstValSpecialStatic;
21039 return_type->type = ira->codegen->builtin_types.entry_type;20295 return_type->type = ira->codegen->builtin_types.entry_type;
21040 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;20296 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
21041 fields[3].data.x_optional = return_type;20297 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;
21055 }20298 }
21056 // args: []TypeInfo.FnArg20299 // args: []TypeInfo.FnArg
21057 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);20300 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...@@ -21067,10 +20310,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21067 fn_arg_array->data.x_array.special = ConstArraySpecialNone;20310 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
21068 fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);20311 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++)20315 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
21073 {
21074 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];20316 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
21075 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index];20317 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...@@ -21117,6 +20359,8 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2111720359
21118 break;20360 break;
21119 }20361 }
20362 case ZigTypeIdFnFrame:
20363 zig_panic("TODO @typeInfo for async function frames");
21120 }20364 }
2112120365
21122 assert(result != nullptr);20366 assert(result != nullptr);
...@@ -22830,11 +22074,45 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns...@@ -22830,11 +22074,45 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns
22830 return result;22074 return result;
22831}22075}
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
22834 IrInstruction *result = ir_build_handle(&ira->new_irb, instruction->base.scope, instruction->base.source_node);22088 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);22089 result->value.type = ptr_frame_type;
22836 assert(fn_entry != nullptr);22090 return result;
22837 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);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;
22838 return result;22116 return result;
22839}22117}
2284022118
...@@ -22869,7 +22147,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -22869,7 +22147,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
22869 case ZigTypeIdInt:22147 case ZigTypeIdInt:
22870 case ZigTypeIdFloat:22148 case ZigTypeIdFloat:
22871 case ZigTypeIdPointer:22149 case ZigTypeIdPointer:
22872 case ZigTypeIdPromise:
22873 case ZigTypeIdArray:22150 case ZigTypeIdArray:
22874 case ZigTypeIdStruct:22151 case ZigTypeIdStruct:
22875 case ZigTypeIdOptional:22152 case ZigTypeIdOptional:
...@@ -22879,6 +22156,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -22879,6 +22156,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
22879 case ZigTypeIdUnion:22156 case ZigTypeIdUnion:
22880 case ZigTypeIdFn:22157 case ZigTypeIdFn:
22881 case ZigTypeIdVector:22158 case ZigTypeIdVector:
22159 case ZigTypeIdFnFrame:
22160 case ZigTypeIdAnyFrame:
22882 {22161 {
22883 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);22162 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
22884 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);22163 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
...@@ -22993,19 +22272,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr...@@ -22993,19 +22272,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
22993 return result;22272 return result;
22994}22273}
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
23009static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,22275static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,
23010 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {22276 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {
23011 if (float_type->id == ZigTypeIdComptimeFloat) {22277 if (float_type->id == ZigTypeIdComptimeFloat) {
...@@ -23130,11 +22396,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct...@@ -23130,11 +22396,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
23130 if (type_is_invalid(base_ptr->value.type))22396 if (type_is_invalid(base_ptr->value.type))
23131 return ira->codegen->invalid_instruction;22397 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
23134 ZigType *type_entry = value->value.type;22406 ZigType *type_entry = value->value.type;
23135 if (type_is_invalid(type_entry))22407 if (type_is_invalid(type_entry))
23136 return ira->codegen->invalid_instruction;22408 return ira->codegen->invalid_instruction;
23137
23138 if (type_entry->id == ZigTypeIdErrorUnion) {22409 if (type_entry->id == ZigTypeIdErrorUnion) {
23139 if (instr_is_comptime(value)) {22410 if (instr_is_comptime(value)) {
23140 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);22411 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
...@@ -23428,18 +22699,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct...@@ -23428,18 +22699,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
23428 return ira->codegen->invalid_instruction;22699 return ira->codegen->invalid_instruction;
23429 }22700 }
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
23443 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));22702 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
23444}22703}
2344522704
...@@ -23678,7 +22937,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *...@@ -23678,7 +22937,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
23678 if (type_is_invalid(statement_type))22937 if (type_is_invalid(statement_type))
23679 return ira->codegen->invalid_instruction;22938 return ira->codegen->invalid_instruction;
2368022939
23681 if (statement_type->id != ZigTypeIdVoid) {22940 if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) {
23682 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));22941 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
23683 }22942 }
2368422943
...@@ -23933,7 +23192,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -23933,7 +23192,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
23933 case ZigTypeIdEnumLiteral:23192 case ZigTypeIdEnumLiteral:
23934 case ZigTypeIdUndefined:23193 case ZigTypeIdUndefined:
23935 case ZigTypeIdNull:23194 case ZigTypeIdNull:
23936 case ZigTypeIdPromise:
23937 case ZigTypeIdErrorUnion:23195 case ZigTypeIdErrorUnion:
23938 case ZigTypeIdErrorSet:23196 case ZigTypeIdErrorSet:
23939 zig_unreachable();23197 zig_unreachable();
...@@ -24043,6 +23301,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -24043,6 +23301,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
24043 zig_panic("TODO buf_write_value_bytes fn type");23301 zig_panic("TODO buf_write_value_bytes fn type");
24044 case ZigTypeIdUnion:23302 case ZigTypeIdUnion:
24045 zig_panic("TODO buf_write_value_bytes union type");23303 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");
24046 }23308 }
24047 zig_unreachable();23309 zig_unreachable();
24048}23310}
...@@ -24087,7 +23349,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou...@@ -24087,7 +23349,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
24087 case ZigTypeIdEnumLiteral:23349 case ZigTypeIdEnumLiteral:
24088 case ZigTypeIdUndefined:23350 case ZigTypeIdUndefined:
24089 case ZigTypeIdNull:23351 case ZigTypeIdNull:
24090 case ZigTypeIdPromise:
24091 zig_unreachable();23352 zig_unreachable();
24092 case ZigTypeIdVoid:23353 case ZigTypeIdVoid:
24093 return ErrorNone;23354 return ErrorNone;
...@@ -24223,6 +23484,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou...@@ -24223,6 +23484,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
24223 zig_panic("TODO buf_read_value_bytes fn type");23484 zig_panic("TODO buf_read_value_bytes fn type");
24224 case ZigTypeIdUnion:23485 case ZigTypeIdUnion:
24225 zig_panic("TODO buf_read_value_bytes union type");23486 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");
24226 }23491 }
24227 zig_unreachable();23492 zig_unreachable();
24228}23493}
...@@ -24573,184 +23838,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct...@@ -24573,184 +23838,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
24573 }23838 }
24574}23839}
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
24754static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {23841static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
24755 ZigType *operand_type = ir_resolve_type(ira, op);23842 ZigType *operand_type = ir_resolve_type(ira, op);
24756 if (type_is_invalid(operand_type))23843 if (type_is_invalid(operand_type))
...@@ -24882,65 +23969,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr...@@ -24882,65 +23969,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
24882 return result;23969 return result;
24883}23970}
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
24944static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {23972static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
24945 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,23973 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
24946 instruction->base.source_node);23974 instruction->base.source_node);
...@@ -24948,17 +23976,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I...@@ -24948,17 +23976,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I
24948 return result;23976 return result;
24949}23977}
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
24962static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,23979static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
24963 ConstExprValue *op, ConstExprValue *out_val) {23980 ConstExprValue *op, ConstExprValue *out_val) {
24964 assert(ira && source_instr && float_type && out_val && op);23981 assert(ira && source_instr && float_type && out_val && op);
...@@ -25485,6 +24502,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i...@@ -25485,6 +24502,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i
25485 union_type, field_name, field_result_loc, result_loc);24502 union_type, field_name, field_result_loc, result_loc);
25486}24503}
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
25488static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24661static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
25489 switch (instruction->id) {24662 switch (instruction->id) {
25490 case IrInstructionIdInvalid:24663 case IrInstructionIdInvalid:
...@@ -25512,6 +24685,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25512,6 +24685,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25512 case IrInstructionIdSliceGen:24685 case IrInstructionIdSliceGen:
25513 case IrInstructionIdRefGen:24686 case IrInstructionIdRefGen:
25514 case IrInstructionIdTestErrGen:24687 case IrInstructionIdTestErrGen:
24688 case IrInstructionIdFrameSizeGen:
24689 case IrInstructionIdAwaitGen:
25515 zig_unreachable();24690 zig_unreachable();
2551624691
25517 case IrInstructionIdReturn:24692 case IrInstructionIdReturn:
...@@ -25552,6 +24727,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25552,6 +24727,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25552 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);24727 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);
25553 case IrInstructionIdSetFloatMode:24728 case IrInstructionIdSetFloatMode:
25554 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);24729 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);
24730 case IrInstructionIdAnyFrameType:
24731 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
25555 case IrInstructionIdSliceType:24732 case IrInstructionIdSliceType:
25556 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);24733 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
25557 case IrInstructionIdGlobalAsm:24734 case IrInstructionIdGlobalAsm:
...@@ -25560,8 +24737,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25560,8 +24737,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25560 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);24737 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
25561 case IrInstructionIdArrayType:24738 case IrInstructionIdArrayType:
25562 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);24739 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
25563 case IrInstructionIdPromiseType:
25564 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
25565 case IrInstructionIdSizeOf:24740 case IrInstructionIdSizeOf:
25566 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);24741 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
25567 case IrInstructionIdTestNonNull:24742 case IrInstructionIdTestNonNull:
...@@ -25660,8 +24835,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25660,8 +24835,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25660 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);24835 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
25661 case IrInstructionIdFrameAddress:24836 case IrInstructionIdFrameAddress:
25662 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);24837 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
25663 case IrInstructionIdHandle:24838 case IrInstructionIdFrameHandle:
25664 return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);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);
25665 case IrInstructionIdAlignOf:24844 case IrInstructionIdAlignOf:
25666 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);24845 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
25667 case IrInstructionIdOverflowOp:24846 case IrInstructionIdOverflowOp:
...@@ -25716,8 +24895,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25716,8 +24895,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25716 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);24895 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);
25717 case IrInstructionIdResetResult:24896 case IrInstructionIdResetResult:
25718 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);24897 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);
25719 case IrInstructionIdResultPtr:
25720 return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction);
25721 case IrInstructionIdOpaqueType:24898 case IrInstructionIdOpaqueType:
25722 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);24899 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
25723 case IrInstructionIdSetAlignStack:24900 case IrInstructionIdSetAlignStack:
...@@ -25732,50 +24909,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25732,50 +24909,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25732 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);24909 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
25733 case IrInstructionIdErrorUnion:24910 case IrInstructionIdErrorUnion:
25734 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);24911 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);
25763 case IrInstructionIdAtomicRmw:24912 case IrInstructionIdAtomicRmw:
25764 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);24913 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
25765 case IrInstructionIdAtomicLoad:24914 case IrInstructionIdAtomicLoad:
25766 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);24915 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);
25771 case IrInstructionIdSaveErrRetAddr:24916 case IrInstructionIdSaveErrRetAddr:
25772 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);24917 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
25773 case IrInstructionIdAddImplicitReturnType:24918 case IrInstructionIdAddImplicitReturnType:
25774 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);24919 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);
25779 case IrInstructionIdFloatOp:24920 case IrInstructionIdFloatOp:
25780 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);24921 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
25781 case IrInstructionIdMulAdd:24922 case IrInstructionIdMulAdd:
...@@ -25802,6 +24943,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25802,6 +24943,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25802 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);24943 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);
25803 case IrInstructionIdUnionInitNamedField:24944 case IrInstructionIdUnionInitNamedField:
25804 return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction);24945 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);
25805 }24958 }
25806 zig_unreachable();24959 zig_unreachable();
25807}24960}
...@@ -25818,9 +24971,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_...@@ -25818,9 +24971,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
25818 old_exec->analysis = ira;24971 old_exec->analysis = ira;
25819 ira->codegen = codegen;24972 ira->codegen = codegen;
2582024973
25821 ZigFn *fn_entry = exec_fn_entry(old_exec);24974 ira->explicit_return_type = expected_type;
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;
25824 ira->explicit_return_type_source_node = expected_type_source_node;24975 ira->explicit_return_type_source_node = expected_type_source_node;
2582524976
25826 ira->old_irb.codegen = codegen;24977 ira->old_irb.codegen = codegen;
...@@ -25918,19 +25069,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25918,19 +25069,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25918 case IrInstructionIdPtrType:25069 case IrInstructionIdPtrType:
25919 case IrInstructionIdSetAlignStack:25070 case IrInstructionIdSetAlignStack:
25920 case IrInstructionIdExport:25071 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:
25930 case IrInstructionIdSaveErrRetAddr:25072 case IrInstructionIdSaveErrRetAddr:
25931 case IrInstructionIdAddImplicitReturnType:25073 case IrInstructionIdAddImplicitReturnType:
25932 case IrInstructionIdMergeErrRetTraces:
25933 case IrInstructionIdMarkErrRetTracePtr:
25934 case IrInstructionIdAtomicRmw:25074 case IrInstructionIdAtomicRmw:
25935 case IrInstructionIdCmpxchgGen:25075 case IrInstructionIdCmpxchgGen:
25936 case IrInstructionIdCmpxchgSrc:25076 case IrInstructionIdCmpxchgSrc:
...@@ -25945,6 +25085,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25945,6 +25085,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25945 case IrInstructionIdOptionalWrap:25085 case IrInstructionIdOptionalWrap:
25946 case IrInstructionIdVectorToArray:25086 case IrInstructionIdVectorToArray:
25947 case IrInstructionIdResetResult:25087 case IrInstructionIdResetResult:
25088 case IrInstructionIdSuspendBegin:
25089 case IrInstructionIdSuspendFinish:
25090 case IrInstructionIdResume:
25091 case IrInstructionIdAwaitSrc:
25092 case IrInstructionIdAwaitGen:
25093 case IrInstructionIdSpillBegin:
25948 return true;25094 return true;
2594925095
25950 case IrInstructionIdPhi:25096 case IrInstructionIdPhi:
...@@ -25963,8 +25109,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25963,8 +25109,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25963 case IrInstructionIdTypeOf:25109 case IrInstructionIdTypeOf:
25964 case IrInstructionIdStructFieldPtr:25110 case IrInstructionIdStructFieldPtr:
25965 case IrInstructionIdArrayType:25111 case IrInstructionIdArrayType:
25966 case IrInstructionIdPromiseType:
25967 case IrInstructionIdSliceType:25112 case IrInstructionIdSliceType:
25113 case IrInstructionIdAnyFrameType:
25968 case IrInstructionIdSizeOf:25114 case IrInstructionIdSizeOf:
25969 case IrInstructionIdTestNonNull:25115 case IrInstructionIdTestNonNull:
25970 case IrInstructionIdOptionalUnwrapPtr:25116 case IrInstructionIdOptionalUnwrapPtr:
...@@ -25990,7 +25136,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25990,7 +25136,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25990 case IrInstructionIdAlignOf:25136 case IrInstructionIdAlignOf:
25991 case IrInstructionIdReturnAddress:25137 case IrInstructionIdReturnAddress:
25992 case IrInstructionIdFrameAddress:25138 case IrInstructionIdFrameAddress:
25993 case IrInstructionIdHandle:25139 case IrInstructionIdFrameHandle:
25140 case IrInstructionIdFrameType:
25141 case IrInstructionIdFrameSizeSrc:
25142 case IrInstructionIdFrameSizeGen:
25994 case IrInstructionIdTestErrSrc:25143 case IrInstructionIdTestErrSrc:
25995 case IrInstructionIdTestErrGen:25144 case IrInstructionIdTestErrGen:
25996 case IrInstructionIdFnProto:25145 case IrInstructionIdFnProto:
...@@ -26023,13 +25172,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -26023,13 +25172,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
26023 case IrInstructionIdTagType:25172 case IrInstructionIdTagType:
26024 case IrInstructionIdErrorReturnTrace:25173 case IrInstructionIdErrorReturnTrace:
26025 case IrInstructionIdErrorUnion:25174 case IrInstructionIdErrorUnion:
26026 case IrInstructionIdGetImplicitAllocator:
26027 case IrInstructionIdCoroAlloc:
26028 case IrInstructionIdCoroSize:
26029 case IrInstructionIdCoroSuspend:
26030 case IrInstructionIdCoroFree:
26031 case IrInstructionIdCoroPromise:
26032 case IrInstructionIdPromiseResultType:
26033 case IrInstructionIdFloatOp:25175 case IrInstructionIdFloatOp:
26034 case IrInstructionIdMulAdd:25176 case IrInstructionIdMulAdd:
26035 case IrInstructionIdAtomicLoad:25177 case IrInstructionIdAtomicLoad:
...@@ -26046,7 +25188,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -26046,7 +25188,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
26046 case IrInstructionIdHasDecl:25188 case IrInstructionIdHasDecl:
26047 case IrInstructionIdAllocaSrc:25189 case IrInstructionIdAllocaSrc:
26048 case IrInstructionIdAllocaGen:25190 case IrInstructionIdAllocaGen:
26049 case IrInstructionIdResultPtr:25191 case IrInstructionIdSpillEnd:
26050 return false;25192 return false;
2605125193
26052 case IrInstructionIdAsm:25194 case IrInstructionIdAsm:
src/ir.hpp+2
...@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal...@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
28 AstNode *source_node);28 AstNode *source_node);
29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
3030
31void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text);
32
31#endif33#endif
src/ir_print.cpp+109-224
...@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {...@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
64 }64 }
65}65}
6666
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {67static void ir_print_return(IrPrint *irp, IrInstructionReturn *instruction) {
68 fprintf(irp->f, "return ");68 fprintf(irp->f, "return ");
69 if (return_instruction->value != nullptr) {69 ir_print_other_instruction(irp, instruction->operand);
70 ir_print_other_instruction(irp, return_instruction->value);
71 }
72}70}
7371
74static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {72static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
...@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {...@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
257255
258static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {256static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {
259 if (call_instruction->is_async) {257 if (call_instruction->is_async) {
260 fprintf(irp->f, "async");258 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, " ");
267 }259 }
268 if (call_instruction->fn_entry) {260 if (call_instruction->fn_entry) {
269 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));261 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...@@ -284,13 +276,7 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi
284276
285static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {277static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {
286 if (call_instruction->is_async) {278 if (call_instruction->is_async) {
287 fprintf(irp->f, "async");279 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, " ");
294 }280 }
295 if (call_instruction->fn_entry) {281 if (call_instruction->fn_entry) {
296 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));282 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...@@ -477,20 +463,21 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
477 ir_print_other_instruction(irp, instruction->child_type);463 ir_print_other_instruction(irp, instruction->child_type);
478}464}
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
488static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {466static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
489 const char *const_kw = instruction->is_const ? "const " : "";467 const char *const_kw = instruction->is_const ? "const " : "";
490 fprintf(irp->f, "[]%s", const_kw);468 fprintf(irp->f, "[]%s", const_kw);
491 ir_print_other_instruction(irp, instruction->child_type);469 ir_print_other_instruction(irp, instruction->child_type);
492}470}
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
494static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {481static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {
495 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));482 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));
496}483}
...@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst...@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
926 fprintf(irp->f, "@frameAddress()");913 fprintf(irp->f, "@frameAddress()");
927}914}
928915
929static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {916static void ir_print_handle(IrPrint *irp, IrInstructionFrameHandle *instruction) {
930 fprintf(irp->f, "@handle()");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, ")");
931}936}
932937
933static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {938static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
...@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru...@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru
1322 fprintf(irp->f, ")");1327 fprintf(irp->f, ")");
1323}1328}
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
1333static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {1330static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
1334 fprintf(irp->f, "@OpaqueType()");1331 fprintf(irp->f, "@OpaqueType()");
1335}1332}
...@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct...@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
1391 ir_print_other_instruction(irp, instruction->payload);1388 ir_print_other_instruction(irp, instruction->payload);
1392}1389}
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
1498static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {1391static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
1499 fprintf(irp->f, "@atomicRmw(");1392 fprintf(irp->f, "@atomicRmw(");
1500 if (instruction->operand_type != nullptr) {1393 if (instruction->operand_type != nullptr) {
...@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct...@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct
1539 fprintf(irp->f, ")");1432 fprintf(irp->f, ")");
1540}1433}
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
1548static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {1435static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1549 fprintf(irp->f, "@saveErrRetAddr()");1436 fprintf(irp->f, "@saveErrRetAddr()");
1550}1437}
...@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl...@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
1555 fprintf(irp->f, ")");1442 fprintf(irp->f, ")");
1556}1443}
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
1574static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {1445static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
15751446
1576 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));1447 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...@@ -1638,6 +1509,47 @@ static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInit
1638 fprintf(irp->f, ")");1509 fprintf(irp->f, ")");
1639}1510}
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
1641static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1553static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1642 ir_print_prefix(irp, instruction);1554 ir_print_prefix(irp, instruction);
1643 switch (instruction->id) {1555 switch (instruction->id) {
...@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1727 case IrInstructionIdArrayType:1639 case IrInstructionIdArrayType:
1728 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);1640 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
1729 break;1641 break;
1730 case IrInstructionIdPromiseType:
1731 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1732 break;
1733 case IrInstructionIdSliceType:1642 case IrInstructionIdSliceType:
1734 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);1643 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
1735 break;1644 break;
1645 case IrInstructionIdAnyFrameType:
1646 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
1647 break;
1736 case IrInstructionIdGlobalAsm:1648 case IrInstructionIdGlobalAsm:
1737 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);1649 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);
1738 break;1650 break;
...@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1886 case IrInstructionIdFrameAddress:1798 case IrInstructionIdFrameAddress:
1887 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);1799 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
1888 break;1800 break;
1889 case IrInstructionIdHandle:1801 case IrInstructionIdFrameHandle:
1890 ir_print_handle(irp, (IrInstructionHandle *)instruction);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);
1891 break;1812 break;
1892 case IrInstructionIdAlignOf:1813 case IrInstructionIdAlignOf:
1893 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);1814 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
...@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2006 case IrInstructionIdResetResult:1927 case IrInstructionIdResetResult:
2007 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);1928 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);
2008 break;1929 break;
2009 case IrInstructionIdResultPtr:
2010 ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
2011 break;
2012 case IrInstructionIdOpaqueType:1930 case IrInstructionIdOpaqueType:
2013 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);1931 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
2014 break;1932 break;
...@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2030 case IrInstructionIdErrorUnion:1948 case IrInstructionIdErrorUnion:
2031 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);1949 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
2032 break;1950 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;
2072 case IrInstructionIdAtomicRmw:1951 case IrInstructionIdAtomicRmw:
2073 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);1952 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
2074 break;1953 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;
2084 case IrInstructionIdSaveErrRetAddr:1954 case IrInstructionIdSaveErrRetAddr:
2085 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);1955 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
2086 break;1956 break;
2087 case IrInstructionIdAddImplicitReturnType:1957 case IrInstructionIdAddImplicitReturnType:
2088 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);1958 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
2089 break;1959 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;
2096 case IrInstructionIdFloatOp:1960 case IrInstructionIdFloatOp:
2097 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);1961 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
2098 break;1962 break;
...@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2147 case IrInstructionIdUnionInitNamedField:2011 case IrInstructionIdUnionInitNamedField:
2148 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);2012 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);
2149 break;2013 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;
2150 }2035 }
2151 fprintf(irp->f, "\n");2036 fprintf(irp->f, "\n");
2152}2037}
src/parser.cpp+11-35
...@@ -282,8 +282,8 @@ static AstNode *ast_parse_prefix_op_expr(...@@ -282,8 +282,8 @@ static AstNode *ast_parse_prefix_op_expr(
282 case NodeTypeAwaitExpr:282 case NodeTypeAwaitExpr:
283 right = &prefix->data.await_expr.expr;283 right = &prefix->data.await_expr.expr;
284 break;284 break;
285 case NodeTypePromiseType:285 case NodeTypeAnyFrameType:
286 right = &prefix->data.promise_type.payload_type;286 right = &prefix->data.anyframe_type.payload_type;
287 break;287 break;
288 case NodeTypeArrayType:288 case NodeTypeArrayType:
289 right = &prefix->data.array_type.child_type;289 right = &prefix->data.array_type.child_type;
...@@ -1167,7 +1167,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {...@@ -1167,7 +1167,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
1167// <- AsmExpr1167// <- AsmExpr
1168// / IfExpr1168// / IfExpr
1169// / KEYWORD_break BreakLabel? Expr?1169// / KEYWORD_break BreakLabel? Expr?
1170// / KEYWORD_cancel Expr
1171// / KEYWORD_comptime Expr1170// / KEYWORD_comptime Expr
1172// / KEYWORD_continue BreakLabel?1171// / KEYWORD_continue BreakLabel?
1173// / KEYWORD_resume Expr1172// / KEYWORD_resume Expr
...@@ -1195,14 +1194,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {...@@ -1195,14 +1194,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
1195 return res;1194 return res;
1196 }1195 }
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
1206 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);1197 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);
1207 if (comptime != nullptr) {1198 if (comptime != nullptr) {
1208 AstNode *expr = ast_expect(pc, ast_parse_expr);1199 AstNode *expr = ast_expect(pc, ast_parse_expr);
...@@ -1643,9 +1634,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {...@@ -1643,9 +1634,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
1643 if (null != nullptr)1634 if (null != nullptr)
1644 return ast_create_node(pc, NodeTypeNullLiteral, null);1635 return ast_create_node(pc, NodeTypeNullLiteral, null);
16451636
1646 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);1637 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
1647 if (promise != nullptr)1638 if (anyframe != nullptr)
1648 return ast_create_node(pc, NodeTypePromiseType, promise);1639 return ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
16491640
1650 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);1641 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);
1651 if (true_token != nullptr) {1642 if (true_token != nullptr) {
...@@ -2042,11 +2033,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {...@@ -2042,11 +2033,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
2042 }2033 }
2043 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {2034 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {
2044 res.cc = CallingConventionAsync;2035 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);
2050 return Optional<AstNodeFnProto>::some(res);2036 return Optional<AstNodeFnProto>::some(res);
2051 }2037 }
20522038
...@@ -2522,7 +2508,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {...@@ -2522,7 +2508,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
25222508
2523// PrefixTypeOp2509// PrefixTypeOp
2524// <- QUESTIONMARK2510// <- QUESTIONMARK
2525// / KEYWORD_promise MINUSRARROW2511// / KEYWORD_anyframe MINUSRARROW
2526// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*2512// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
2527// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*2513// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
2528static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {2514static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
...@@ -2533,10 +2519,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {...@@ -2533,10 +2519,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
2533 return res;2519 return res;
2534 }2520 }
25352521
2536 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);2522 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
2537 if (promise != nullptr) {2523 if (anyframe != nullptr) {
2538 if (eat_token_if(pc, TokenIdArrow) != nullptr) {2524 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);
2540 return res;2526 return res;
2541 }2527 }
25422528
...@@ -2680,11 +2666,6 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {...@@ -2680,11 +2666,6 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
2680 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);2666 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
2681 res->data.fn_call_expr.is_async = true;2667 res->data.fn_call_expr.is_async = true;
2682 res->data.fn_call_expr.seen = false;2668 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
2689 return res;2670 return res;
2690}2671}
...@@ -2858,7 +2839,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2858,7 +2839,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2858 visit_node_list(&node->data.fn_proto.params, visit, context);2839 visit_node_list(&node->data.fn_proto.params, visit, context);
2859 visit_field(&node->data.fn_proto.align_expr, visit, context);2840 visit_field(&node->data.fn_proto.align_expr, visit, context);
2860 visit_field(&node->data.fn_proto.section_expr, visit, context);2841 visit_field(&node->data.fn_proto.section_expr, visit, context);
2861 visit_field(&node->data.fn_proto.async_allocator_type, visit, context);
2862 break;2842 break;
2863 case NodeTypeFnDef:2843 case NodeTypeFnDef:
2864 visit_field(&node->data.fn_def.fn_proto, visit, context);2844 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...@@ -2918,7 +2898,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2918 case NodeTypeFnCallExpr:2898 case NodeTypeFnCallExpr:
2919 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);2899 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
2920 visit_node_list(&node->data.fn_call_expr.params, visit, context);2900 visit_node_list(&node->data.fn_call_expr.params, visit, context);
2921 visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
2922 break;2901 break;
2923 case NodeTypeArrayAccessExpr:2902 case NodeTypeArrayAccessExpr:
2924 visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);2903 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...@@ -3034,8 +3013,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3034 case NodeTypeInferredArrayType:3013 case NodeTypeInferredArrayType:
3035 visit_field(&node->data.array_type.child_type, visit, context);3014 visit_field(&node->data.array_type.child_type, visit, context);
3036 break;3015 break;
3037 case NodeTypePromiseType:3016 case NodeTypeAnyFrameType:
3038 visit_field(&node->data.promise_type.payload_type, visit, context);3017 visit_field(&node->data.anyframe_type.payload_type, visit, context);
3039 break;3018 break;
3040 case NodeTypeErrorType:3019 case NodeTypeErrorType:
3041 // none3020 // none
...@@ -3047,9 +3026,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3047,9 +3026,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3047 case NodeTypeErrorSetDecl:3026 case NodeTypeErrorSetDecl:
3048 visit_node_list(&node->data.err_set_decl.decls, visit, context);3027 visit_node_list(&node->data.err_set_decl.decls, visit, context);
3049 break;3028 break;
3050 case NodeTypeCancel:
3051 visit_field(&node->data.cancel_expr.expr, visit, context);
3052 break;
3053 case NodeTypeResume:3029 case NodeTypeResume:
3054 visit_field(&node->data.resume_expr.expr, visit, context);3030 visit_field(&node->data.resume_expr.expr, visit, context);
3055 break;3031 break;
src/target.cpp+4
...@@ -1759,3 +1759,7 @@ bool target_supports_libunwind(const ZigTarget *target) {...@@ -1759,3 +1759,7 @@ bool target_supports_libunwind(const ZigTarget *target) {
1759 return true;1759 return true;
1760}1760}
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);...@@ -197,4 +197,6 @@ uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
197size_t target_libc_count(void);197size_t target_libc_count(void);
198void target_libc_enum(size_t index, ZigTarget *out_target);198void target_libc_enum(size_t index, ZigTarget *out_target);
199199
200unsigned target_fn_align(const ZigTarget *target);
201
200#endif202#endif
src/tokenizer.cpp+2-4
...@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {
109 {"align", TokenIdKeywordAlign},109 {"align", TokenIdKeywordAlign},
110 {"allowzero", TokenIdKeywordAllowZero},110 {"allowzero", TokenIdKeywordAllowZero},
111 {"and", TokenIdKeywordAnd},111 {"and", TokenIdKeywordAnd},
112 {"anyframe", TokenIdKeywordAnyFrame},
112 {"asm", TokenIdKeywordAsm},113 {"asm", TokenIdKeywordAsm},
113 {"async", TokenIdKeywordAsync},114 {"async", TokenIdKeywordAsync},
114 {"await", TokenIdKeywordAwait},115 {"await", TokenIdKeywordAwait},
115 {"break", TokenIdKeywordBreak},116 {"break", TokenIdKeywordBreak},
116 {"cancel", TokenIdKeywordCancel},
117 {"catch", TokenIdKeywordCatch},117 {"catch", TokenIdKeywordCatch},
118 {"comptime", TokenIdKeywordCompTime},118 {"comptime", TokenIdKeywordCompTime},
119 {"const", TokenIdKeywordConst},119 {"const", TokenIdKeywordConst},
...@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {
136 {"or", TokenIdKeywordOr},136 {"or", TokenIdKeywordOr},
137 {"orelse", TokenIdKeywordOrElse},137 {"orelse", TokenIdKeywordOrElse},
138 {"packed", TokenIdKeywordPacked},138 {"packed", TokenIdKeywordPacked},
139 {"promise", TokenIdKeywordPromise},
140 {"pub", TokenIdKeywordPub},139 {"pub", TokenIdKeywordPub},
141 {"resume", TokenIdKeywordResume},140 {"resume", TokenIdKeywordResume},
142 {"return", TokenIdKeywordReturn},141 {"return", TokenIdKeywordReturn},
...@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {...@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {
1531 case TokenIdKeywordAwait: return "await";1530 case TokenIdKeywordAwait: return "await";
1532 case TokenIdKeywordResume: return "resume";1531 case TokenIdKeywordResume: return "resume";
1533 case TokenIdKeywordSuspend: return "suspend";1532 case TokenIdKeywordSuspend: return "suspend";
1534 case TokenIdKeywordCancel: return "cancel";
1535 case TokenIdKeywordAlign: return "align";1533 case TokenIdKeywordAlign: return "align";
1536 case TokenIdKeywordAnd: return "and";1534 case TokenIdKeywordAnd: return "and";
1535 case TokenIdKeywordAnyFrame: return "anyframe";
1537 case TokenIdKeywordAsm: return "asm";1536 case TokenIdKeywordAsm: return "asm";
1538 case TokenIdKeywordBreak: return "break";1537 case TokenIdKeywordBreak: return "break";
1539 case TokenIdKeywordCatch: return "catch";1538 case TokenIdKeywordCatch: return "catch";
...@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {...@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {
1558 case TokenIdKeywordOr: return "or";1557 case TokenIdKeywordOr: return "or";
1559 case TokenIdKeywordOrElse: return "orelse";1558 case TokenIdKeywordOrElse: return "orelse";
1560 case TokenIdKeywordPacked: return "packed";1559 case TokenIdKeywordPacked: return "packed";
1561 case TokenIdKeywordPromise: return "promise";
1562 case TokenIdKeywordPub: return "pub";1560 case TokenIdKeywordPub: return "pub";
1563 case TokenIdKeywordReturn: return "return";1561 case TokenIdKeywordReturn: return "return";
1564 case TokenIdKeywordLinkSection: return "linksection";1562 case TokenIdKeywordLinkSection: return "linksection";
src/tokenizer.hpp+1-2
...@@ -53,11 +53,11 @@ enum TokenId {...@@ -53,11 +53,11 @@ enum TokenId {
53 TokenIdKeywordAlign,53 TokenIdKeywordAlign,
54 TokenIdKeywordAllowZero,54 TokenIdKeywordAllowZero,
55 TokenIdKeywordAnd,55 TokenIdKeywordAnd,
56 TokenIdKeywordAnyFrame,
56 TokenIdKeywordAsm,57 TokenIdKeywordAsm,
57 TokenIdKeywordAsync,58 TokenIdKeywordAsync,
58 TokenIdKeywordAwait,59 TokenIdKeywordAwait,
59 TokenIdKeywordBreak,60 TokenIdKeywordBreak,
60 TokenIdKeywordCancel,
61 TokenIdKeywordCatch,61 TokenIdKeywordCatch,
62 TokenIdKeywordCompTime,62 TokenIdKeywordCompTime,
63 TokenIdKeywordConst,63 TokenIdKeywordConst,
...@@ -81,7 +81,6 @@ enum TokenId {...@@ -81,7 +81,6 @@ enum TokenId {
81 TokenIdKeywordOr,81 TokenIdKeywordOr,
82 TokenIdKeywordOrElse,82 TokenIdKeywordOrElse,
83 TokenIdKeywordPacked,83 TokenIdKeywordPacked,
84 TokenIdKeywordPromise,
85 TokenIdKeywordPub,84 TokenIdKeywordPub,
86 TokenIdKeywordResume,85 TokenIdKeywordResume,
87 TokenIdKeywordReturn,86 TokenIdKeywordReturn,
src/zig_llvm.cpp+8-3
...@@ -42,7 +42,6 @@...@@ -42,7 +42,6 @@
42#include <llvm/Support/TargetRegistry.h>42#include <llvm/Support/TargetRegistry.h>
43#include <llvm/Target/TargetMachine.h>43#include <llvm/Target/TargetMachine.h>
44#include <llvm/Target/CodeGenCWrappers.h>44#include <llvm/Target/CodeGenCWrappers.h>
45#include <llvm/Transforms/Coroutines.h>
46#include <llvm/Transforms/IPO.h>45#include <llvm/Transforms/IPO.h>
47#include <llvm/Transforms/IPO/AlwaysInliner.h>46#include <llvm/Transforms/IPO/AlwaysInliner.h>
48#include <llvm/Transforms/IPO/PassManagerBuilder.h>47#include <llvm/Transforms/IPO/PassManagerBuilder.h>
...@@ -203,8 +202,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -203,8 +202,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
203 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);202 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
204 }203 }
205204
206 addCoroutinePassesToExtensionPoints(*PMBuilder);
207
208 // Set up the per-function pass manager.205 // Set up the per-function pass manager.
209 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);206 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
210 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);207 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
...@@ -898,6 +895,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV...@@ -898,6 +895,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
898 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));895 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
899}896}
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
902class MyOStream: public raw_ostream {907class MyOStream: public raw_ostream {
903 public:908 public:
src/zig_llvm.h+2
...@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde...@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde
211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
212212
213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);213ZIG_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
215ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);217ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
216ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);218ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
std/event/channel.zig+45-72
...@@ -2,8 +2,6 @@ const std = @import("../std.zig");...@@ -2,8 +2,6 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const Loop = std.event.Loop;5const Loop = std.event.Loop;
86
9/// many producer, many consumer, thread-safe, runtime configurable buffer size7/// many producer, many consumer, thread-safe, runtime configurable buffer size
...@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {...@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {
77 /// must be called when all calls to put and get have suspended and no more calls occur75 /// must be called when all calls to put and get have suspended and no more calls occur
78 pub fn destroy(self: *SelfChannel) void {76 pub fn destroy(self: *SelfChannel) void {
79 while (self.getters.get()) |get_node| {77 while (self.getters.get()) |get_node| {
80 cancel get_node.data.tick_node.data;78 resume get_node.data.tick_node.data;
81 }79 }
82 while (self.putters.get()) |put_node| {80 while (self.putters.get()) |put_node| {
83 cancel put_node.data.tick_node.data;81 resume put_node.data.tick_node.data;
84 }82 }
85 self.loop.allocator.free(self.buffer_nodes);83 self.loop.allocator.free(self.buffer_nodes);
86 self.loop.allocator.destroy(self);84 self.loop.allocator.destroy(self);
87 }85 }
8886
89 /// puts a data item in the channel. The promise completes when the value has been added to the87 /// puts a data item in the channel. The function returns when the value has been added to the
90 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.88 /// 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 {89 /// Or when the channel is destroyed.
92 // TODO fix this workaround90 pub fn put(self: *SelfChannel, data: T) void {
93 suspend {91 var my_tick_node = Loop.NextTickNode.init(@frame());
94 resume @handle();
95 }
96
97 var my_tick_node = Loop.NextTickNode.init(@handle());
98 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{92 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{
99 .tick_node = &my_tick_node,93 .tick_node = &my_tick_node,
100 .data = data,94 .data = data,
...@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {...@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {
10296
103 // TODO test canceling a put()97 // TODO test canceling a put()
104 errdefer {98 errdefer {
105 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);99 _ = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
106 const need_dispatch = !self.putters.remove(&queue_node);100 const need_dispatch = !self.putters.remove(&queue_node);
107 self.loop.cancelOnNextTick(&my_tick_node);101 self.loop.cancelOnNextTick(&my_tick_node);
108 if (need_dispatch) {102 if (need_dispatch) {
109 // oops we made the put_count incorrect for a period of time. fix by dispatching.103 // 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);
111 self.dispatch();105 self.dispatch();
112 }106 }
113 }107 }
114 suspend {108 suspend {
115 self.putters.put(&queue_node);109 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
118 self.dispatch();112 self.dispatch();
119 }113 }
120 }114 }
121115
122 /// await this function to get an item from the channel. If the buffer is empty, the promise will116 /// await this function to get an item from the channel. If the buffer is empty, the frame will
123 /// complete when the next item is put in the channel.117 /// complete when the next item is put in the channel.
124 pub async fn get(self: *SelfChannel) T {118 pub async fn get(self: *SelfChannel) T {
125 // TODO fix this workaround119 // TODO https://github.com/ziglang/zig/issues/2765
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
132 var result: T = undefined;120 var result: T = undefined;
133 var my_tick_node = Loop.NextTickNode.init(@handle());121 var my_tick_node = Loop.NextTickNode.init(@frame());
134 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{122 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
135 .tick_node = &my_tick_node,123 .tick_node = &my_tick_node,
136 .data = GetNode.Data{124 .data = GetNode.Data{
...@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {...@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {
140128
141 // TODO test canceling a get()129 // TODO test canceling a get()
142 errdefer {130 errdefer {
143 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);131 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
144 const need_dispatch = !self.getters.remove(&queue_node);132 const need_dispatch = !self.getters.remove(&queue_node);
145 self.loop.cancelOnNextTick(&my_tick_node);133 self.loop.cancelOnNextTick(&my_tick_node);
146 if (need_dispatch) {134 if (need_dispatch) {
147 // oops we made the get_count incorrect for a period of time. fix by dispatching.135 // 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);
149 self.dispatch();137 self.dispatch();
150 }138 }
151 }139 }
152140
153 suspend {141 suspend {
154 self.getters.put(&queue_node);142 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
157 self.dispatch();145 self.dispatch();
158 }146 }
...@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {...@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {
173 /// Await is necessary for locking purposes. The function will be resumed after checking the channel161 /// Await is necessary for locking purposes. The function will be resumed after checking the channel
174 /// for data and will not wait for data to be available.162 /// for data and will not wait for data to be available.
175 pub async fn getOrNull(self: *SelfChannel) ?T {163 pub async fn getOrNull(self: *SelfChannel) ?T {
176 // TODO fix this workaround
177 suspend {
178 resume @handle();
179 }
180
181 // TODO integrate this function with named return values164 // TODO integrate this function with named return values
182 // so we can get rid of this extra result copy165 // so we can get rid of this extra result copy
183 var result: ?T = null;166 var result: ?T = null;
184 var my_tick_node = Loop.NextTickNode.init(@handle());167 var my_tick_node = Loop.NextTickNode.init(@frame());
185 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);168 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);
186 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{169 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
187 .tick_node = &my_tick_node,170 .tick_node = &my_tick_node,
...@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {...@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {
197 // TODO test canceling getOrNull180 // TODO test canceling getOrNull
198 errdefer {181 errdefer {
199 _ = self.or_null_queue.remove(&or_null_node);182 _ = 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);
201 const need_dispatch = !self.getters.remove(&queue_node);184 const need_dispatch = !self.getters.remove(&queue_node);
202 self.loop.cancelOnNextTick(&my_tick_node);185 self.loop.cancelOnNextTick(&my_tick_node);
203 if (need_dispatch) {186 if (need_dispatch) {
204 // oops we made the get_count incorrect for a period of time. fix by dispatching.187 // 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);
206 self.dispatch();189 self.dispatch();
207 }190 }
208 }191 }
209192
210 suspend {193 suspend {
211 self.getters.put(&queue_node);194 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);
213 self.or_null_queue.put(&or_null_node);196 self.or_null_queue.put(&or_null_node);
214197
215 self.dispatch();198 self.dispatch();
...@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {...@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {
219202
220 fn dispatch(self: *SelfChannel) void {203 fn dispatch(self: *SelfChannel) void {
221 // set the "need dispatch" flag204 // 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
224 lock: while (true) {207 lock: while (true) {
225 // set the lock flag208 // 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);
227 if (prev_lock != 0) return;210 if (prev_lock != 0) return;
228211
229 // clear the need_dispatch flag since we're about to do it212 // 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
232 while (true) {215 while (true) {
233 one_dispatch: {216 one_dispatch: {
234 // later we correct these extra subtractions217 // later we correct these extra subtractions
235 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);218 var get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
236 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);219 var put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
237220
238 // transfer self.buffer to self.getters221 // transfer self.buffer to self.getters
239 while (self.buffer_len != 0) {222 while (self.buffer_len != 0) {
...@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {...@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {
252 self.loop.onNextTick(get_node.tick_node);235 self.loop.onNextTick(get_node.tick_node);
253 self.buffer_len -= 1;236 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);
256 }239 }
257240
258 // direct transfer self.putters to self.getters241 // direct transfer self.putters to self.getters
...@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {...@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {
272 self.loop.onNextTick(get_node.tick_node);255 self.loop.onNextTick(get_node.tick_node);
273 self.loop.onNextTick(put_node.tick_node);256 self.loop.onNextTick(put_node.tick_node);
274257
275 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);258 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
276 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);259 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
277 }260 }
278261
279 // transfer self.putters to self.buffer262 // transfer self.putters to self.buffer
...@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {...@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {
285 self.buffer_index +%= 1;268 self.buffer_index +%= 1;
286 self.buffer_len += 1;269 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);
289 }272 }
290 }273 }
291274
292 // undo the extra subtractions275 // undo the extra subtractions
293 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);276 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
294 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);277 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
295278
296 // All the "get or null" functions should resume now.279 // All the "get or null" functions should resume now.
297 var remove_count: usize = 0;280 var remove_count: usize = 0;
...@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {...@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {
300 self.loop.onNextTick(or_null_node.data.data.tick_node);283 self.loop.onNextTick(or_null_node.data.data.tick_node);
301 }284 }
302 if (remove_count != 0) {285 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);
304 }287 }
305288
306 // clear need-dispatch flag289 // 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);
308 if (need_dispatch != 0) continue;291 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);
311 assert(my_lock != 0);294 assert(my_lock != 0);
312295
313 // we have to check again now that we unlocked296 // 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
316 return;299 return;
317 }300 }
...@@ -324,51 +307,41 @@ test "std.event.Channel" {...@@ -324,51 +307,41 @@ test "std.event.Channel" {
324 // https://github.com/ziglang/zig/issues/1908307 // https://github.com/ziglang/zig/issues/1908
325 if (builtin.single_threaded) return error.SkipZigTest;308 if (builtin.single_threaded) return error.SkipZigTest;
326309
327 const allocator = std.heap.direct_allocator;
328
329 var loop: Loop = undefined;310 var loop: Loop = undefined;
330 // TODO make a multi threaded test311 // TODO make a multi threaded test
331 try loop.initSingleThreaded(allocator);312 try loop.initSingleThreaded(std.heap.direct_allocator);
332 defer loop.deinit();313 defer loop.deinit();
333314
334 const channel = try Channel(i32).create(&loop, 0);315 const channel = try Channel(i32).create(&loop, 0);
335 defer channel.destroy();316 defer channel.destroy();
336317
337 const handle = try async<allocator> testChannelGetter(&loop, channel);318 const handle = async testChannelGetter(&loop, channel);
338 defer cancel handle;319 const putter = async testChannelPutter(channel);
339
340 const putter = try async<allocator> testChannelPutter(channel);
341 defer cancel putter;
342320
343 loop.run();321 loop.run();
344}322}
345323
346async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {324async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
347 errdefer @panic("test failed");325 const value1 = channel.get();
348
349 const value1_promise = try async channel.get();
350 const value1 = await value1_promise;
351 testing.expect(value1 == 1234);326 testing.expect(value1 == 1234);
352327
353 const value2_promise = try async channel.get();328 const value2 = channel.get();
354 const value2 = await value2_promise;
355 testing.expect(value2 == 4567);329 testing.expect(value2 == 4567);
356330
357 const value3_promise = try async channel.getOrNull();331 const value3 = channel.getOrNull();
358 const value3 = await value3_promise;
359 testing.expect(value3 == null);332 testing.expect(value3 == null);
360333
361 const last_put = try async testPut(channel, 4444);334 const last_put = async testPut(channel, 4444);
362 const value4 = await try async channel.getOrNull();335 const value4 = channel.getOrNull();
363 testing.expect(value4.? == 4444);336 testing.expect(value4.? == 4444);
364 await last_put;337 await last_put;
365}338}
366339
367async fn testChannelPutter(channel: *Channel(i32)) void {340async fn testChannelPutter(channel: *Channel(i32)) void {
368 await (async channel.put(1234) catch @panic("out of memory"));341 channel.put(1234);
369 await (async channel.put(4567) catch @panic("out of memory"));342 channel.put(4567);
370}343}
371344
372async fn testPut(channel: *Channel(i32), value: i32) void {345async fn testPut(channel: *Channel(i32), value: i32) void {
373 await (async channel.put(value) catch @panic("out of memory"));346 channel.put(value);
374}347}
std/event/fs.zig+640-694
...@@ -76,17 +76,13 @@ pub const Request = struct {...@@ -76,17 +76,13 @@ pub const Request = struct {
7676
77pub const PWriteVError = error{OutOfMemory} || File.WriteError;77pub 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.
80pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {80pub 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 }
85 switch (builtin.os) {81 switch (builtin.os) {
86 builtin.Os.macosx,82 .macosx,
87 builtin.Os.linux,83 .linux,
88 builtin.Os.freebsd,84 .freebsd,
89 builtin.Os.netbsd,85 .netbsd,
90 => {86 => {
91 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);87 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
92 defer loop.allocator.free(iovecs);88 defer loop.allocator.free(iovecs);
...@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us...@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
10096
101 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);97 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);
102 },98 },
103 builtin.Os.windows => {99 .windows => {
104 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);100 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);
105 defer loop.allocator.free(data_copy);101 defer loop.allocator.free(data_copy);
106 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);102 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...@@ -109,7 +105,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
109 }105 }
110}106}
111107
112/// data must outlive the returned promise108/// data must outlive the returned frame
113pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {109pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
114 if (data.len == 0) return;110 if (data.len == 0) return;
115 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);111 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...@@ -123,15 +119,10 @@ pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, off
123}119}
124120
125pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {121pub 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
131 var resume_node = Loop.ResumeNode.Basic{122 var resume_node = Loop.ResumeNode.Basic{
132 .base = Loop.ResumeNode{123 .base = Loop.ResumeNode{
133 .id = Loop.ResumeNode.Id.Basic,124 .id = Loop.ResumeNode.Id.Basic,
134 .handle = @handle(),125 .handle = @frame(),
135 .overlapped = windows.OVERLAPPED{126 .overlapped = windows.OVERLAPPED{
136 .Internal = 0,127 .Internal = 0,
137 .InternalHigh = 0,128 .InternalHigh = 0,
...@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)...@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)
166 }157 }
167}158}
168159
169/// iovecs must live until pwritev promise completes.160/// iovecs must live until pwritev frame completes.
170pub async fn pwritevPosix(161pub async fn pwritevPosix(
171 loop: *Loop,162 loop: *Loop,
172 fd: fd_t,163 fd: fd_t,
173 iovecs: []const os.iovec_const,164 iovecs: []const os.iovec_const,
174 offset: usize,165 offset: usize,
175) os.WriteError!void {166) os.WriteError!void {
176 // workaround for https://github.com/ziglang/zig/issues/1194
177 suspend {
178 resume @handle();
179 }
180
181 var req_node = RequestNode{167 var req_node = RequestNode{
182 .prev = null,168 .prev = null,
183 .next = null,169 .next = null,
...@@ -194,7 +180,7 @@ pub async fn pwritevPosix(...@@ -194,7 +180,7 @@ pub async fn pwritevPosix(
194 .TickNode = Loop.NextTickNode{180 .TickNode = Loop.NextTickNode{
195 .prev = null,181 .prev = null,
196 .next = null,182 .next = null,
197 .data = @handle(),183 .data = @frame(),
198 },184 },
199 },185 },
200 },186 },
...@@ -211,19 +197,14 @@ pub async fn pwritevPosix(...@@ -211,19 +197,14 @@ pub async fn pwritevPosix(
211197
212pub const PReadVError = error{OutOfMemory} || File.ReadError;198pub 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.
215pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {201pub 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
221 assert(data.len != 0);202 assert(data.len != 0);
222 switch (builtin.os) {203 switch (builtin.os) {
223 builtin.Os.macosx,204 .macosx,
224 builtin.Os.linux,205 .linux,
225 builtin.Os.freebsd,206 .freebsd,
226 builtin.Os.netbsd,207 .netbsd,
227 => {208 => {
228 const iovecs = try loop.allocator.alloc(os.iovec, data.len);209 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229 defer loop.allocator.free(iovecs);210 defer loop.allocator.free(iovecs);
...@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR...@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
237218
238 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);219 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);
239 },220 },
240 builtin.Os.windows => {221 .windows => {
241 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);222 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);
242 defer loop.allocator.free(data_copy);223 defer loop.allocator.free(data_copy);
243 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);224 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...@@ -246,7 +227,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
246 }227 }
247}228}
248229
249/// data must outlive the returned promise230/// data must outlive the returned frame
250pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {231pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
251 assert(data.len != 0);232 assert(data.len != 0);
252 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);233 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...@@ -272,15 +253,10 @@ pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u6
272}253}
273254
274pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {255pub 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
280 var resume_node = Loop.ResumeNode.Basic{256 var resume_node = Loop.ResumeNode.Basic{
281 .base = Loop.ResumeNode{257 .base = Loop.ResumeNode{
282 .id = Loop.ResumeNode.Id.Basic,258 .id = Loop.ResumeNode.Id.Basic,
283 .handle = @handle(),259 .handle = @frame(),
284 .overlapped = windows.OVERLAPPED{260 .overlapped = windows.OVERLAPPED{
285 .Internal = 0,261 .Internal = 0,
286 .InternalHigh = 0,262 .InternalHigh = 0,
...@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize...@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize
314 return usize(bytes_transferred);290 return usize(bytes_transferred);
315}291}
316292
317/// iovecs must live until preadv promise completes293/// iovecs must live until preadv frame completes
318pub async fn preadvPosix(294pub async fn preadvPosix(
319 loop: *Loop,295 loop: *Loop,
320 fd: fd_t,296 fd: fd_t,
321 iovecs: []const os.iovec,297 iovecs: []const os.iovec,
322 offset: usize,298 offset: usize,
323) os.ReadError!usize {299) os.ReadError!usize {
324 // workaround for https://github.com/ziglang/zig/issues/1194
325 suspend {
326 resume @handle();
327 }
328
329 var req_node = RequestNode{300 var req_node = RequestNode{
330 .prev = null,301 .prev = null,
331 .next = null,302 .next = null,
...@@ -342,7 +313,7 @@ pub async fn preadvPosix(...@@ -342,7 +313,7 @@ pub async fn preadvPosix(
342 .TickNode = Loop.NextTickNode{313 .TickNode = Loop.NextTickNode{
343 .prev = null,314 .prev = null,
344 .next = null,315 .next = null,
345 .data = @handle(),316 .data = @frame(),
346 },317 },
347 },318 },
348 },319 },
...@@ -363,11 +334,6 @@ pub async fn openPosix(...@@ -363,11 +334,6 @@ pub async fn openPosix(
363 flags: u32,334 flags: u32,
364 mode: File.Mode,335 mode: File.Mode,
365) File.OpenError!fd_t {336) File.OpenError!fd_t {
366 // workaround for https://github.com/ziglang/zig/issues/1194
367 suspend {
368 resume @handle();
369 }
370
371 const path_c = try std.os.toPosixPath(path);337 const path_c = try std.os.toPosixPath(path);
372338
373 var req_node = RequestNode{339 var req_node = RequestNode{
...@@ -386,7 +352,7 @@ pub async fn openPosix(...@@ -386,7 +352,7 @@ pub async fn openPosix(
386 .TickNode = Loop.NextTickNode{352 .TickNode = Loop.NextTickNode{
387 .prev = null,353 .prev = null,
388 .next = null,354 .next = null,
389 .data = @handle(),355 .data = @frame(),
390 },356 },
391 },357 },
392 },358 },
...@@ -403,12 +369,12 @@ pub async fn openPosix(...@@ -403,12 +369,12 @@ pub async fn openPosix(
403369
404pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {370pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
405 switch (builtin.os) {371 switch (builtin.os) {
406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {372 .macosx, .linux, .freebsd, .netbsd => {
407 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;373 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
408 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);374 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
409 },375 },
410376
411 builtin.Os.windows => return windows.CreateFile(377 .windows => return windows.CreateFile(
412 path,378 path,
413 windows.GENERIC_READ,379 windows.GENERIC_READ,
414 windows.FILE_SHARE_READ,380 windows.FILE_SHARE_READ,
...@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {...@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
431/// Creates if does not exist. Truncates the file if it exists.397/// Creates if does not exist. Truncates the file if it exists.
432pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {398pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
433 switch (builtin.os) {399 switch (builtin.os) {
434 builtin.Os.macosx,400 .macosx,
435 builtin.Os.linux,401 .linux,
436 builtin.Os.freebsd,402 .freebsd,
437 builtin.Os.netbsd,403 .netbsd,
438 => {404 => {
439 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;405 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
440 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);406 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
441 },407 },
442 builtin.Os.windows => return windows.CreateFile(408 .windows => return windows.CreateFile(
443 path,409 path,
444 windows.GENERIC_WRITE,410 windows.GENERIC_WRITE,
445 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,411 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -459,12 +425,12 @@ pub async fn openReadWrite(...@@ -459,12 +425,12 @@ pub async fn openReadWrite(
459 mode: File.Mode,425 mode: File.Mode,
460) File.OpenError!fd_t {426) File.OpenError!fd_t {
461 switch (builtin.os) {427 switch (builtin.os) {
462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {428 .macosx, .linux, .freebsd, .netbsd => {
463 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;429 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
464 return await (async openPosix(loop, path, flags, mode) catch unreachable);430 return await (async openPosix(loop, path, flags, mode) catch unreachable);
465 },431 },
466432
467 builtin.Os.windows => return windows.CreateFile(433 .windows => return windows.CreateFile(
468 path,434 path,
469 windows.GENERIC_WRITE | windows.GENERIC_READ,435 windows.GENERIC_WRITE | windows.GENERIC_READ,
470 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,436 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -489,9 +455,9 @@ pub const CloseOperation = struct {...@@ -489,9 +455,9 @@ pub const CloseOperation = struct {
489 os_data: OsData,455 os_data: OsData,
490456
491 const OsData = switch (builtin.os) {457 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 {
495 handle: ?fd_t,461 handle: ?fd_t,
496 },462 },
497463
...@@ -508,8 +474,8 @@ pub const CloseOperation = struct {...@@ -508,8 +474,8 @@ pub const CloseOperation = struct {
508 self.* = CloseOperation{474 self.* = CloseOperation{
509 .loop = loop,475 .loop = loop,
510 .os_data = switch (builtin.os) {476 .os_data = switch (builtin.os) {
511 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),477 .linux, .macosx, .freebsd, .netbsd => initOsDataPosix(self),
512 builtin.Os.windows => OsData{ .handle = null },478 .windows => OsData{ .handle = null },
513 else => @compileError("Unsupported OS"),479 else => @compileError("Unsupported OS"),
514 },480 },
515 };481 };
...@@ -535,10 +501,10 @@ pub const CloseOperation = struct {...@@ -535,10 +501,10 @@ pub const CloseOperation = struct {
535 /// Defer this after creating.501 /// Defer this after creating.
536 pub fn finish(self: *CloseOperation) void {502 pub fn finish(self: *CloseOperation) void {
537 switch (builtin.os) {503 switch (builtin.os) {
538 builtin.Os.linux,504 .linux,
539 builtin.Os.macosx,505 .macosx,
540 builtin.Os.freebsd,506 .freebsd,
541 builtin.Os.netbsd,507 .netbsd,
542 => {508 => {
543 if (self.os_data.have_fd) {509 if (self.os_data.have_fd) {
544 self.loop.posixFsRequest(&self.os_data.close_req_node);510 self.loop.posixFsRequest(&self.os_data.close_req_node);
...@@ -546,7 +512,7 @@ pub const CloseOperation = struct {...@@ -546,7 +512,7 @@ pub const CloseOperation = struct {
546 self.loop.allocator.destroy(self);512 self.loop.allocator.destroy(self);
547 }513 }
548 },514 },
549 builtin.Os.windows => {515 .windows => {
550 if (self.os_data.handle) |handle| {516 if (self.os_data.handle) |handle| {
551 os.close(handle);517 os.close(handle);
552 }518 }
...@@ -558,15 +524,15 @@ pub const CloseOperation = struct {...@@ -558,15 +524,15 @@ pub const CloseOperation = struct {
558524
559 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {525 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
560 switch (builtin.os) {526 switch (builtin.os) {
561 builtin.Os.linux,527 .linux,
562 builtin.Os.macosx,528 .macosx,
563 builtin.Os.freebsd,529 .freebsd,
564 builtin.Os.netbsd,530 .netbsd,
565 => {531 => {
566 self.os_data.close_req_node.data.msg.Close.fd = handle;532 self.os_data.close_req_node.data.msg.Close.fd = handle;
567 self.os_data.have_fd = true;533 self.os_data.have_fd = true;
568 },534 },
569 builtin.Os.windows => {535 .windows => {
570 self.os_data.handle = handle;536 self.os_data.handle = handle;
571 },537 },
572 else => @compileError("Unsupported OS"),538 else => @compileError("Unsupported OS"),
...@@ -576,14 +542,14 @@ pub const CloseOperation = struct {...@@ -576,14 +542,14 @@ pub const CloseOperation = struct {
576 /// Undo a `setHandle`.542 /// Undo a `setHandle`.
577 pub fn clearHandle(self: *CloseOperation) void {543 pub fn clearHandle(self: *CloseOperation) void {
578 switch (builtin.os) {544 switch (builtin.os) {
579 builtin.Os.linux,545 .linux,
580 builtin.Os.macosx,546 .macosx,
581 builtin.Os.freebsd,547 .freebsd,
582 builtin.Os.netbsd,548 .netbsd,
583 => {549 => {
584 self.os_data.have_fd = false;550 self.os_data.have_fd = false;
585 },551 },
586 builtin.Os.windows => {552 .windows => {
587 self.os_data.handle = null;553 self.os_data.handle = null;
588 },554 },
589 else => @compileError("Unsupported OS"),555 else => @compileError("Unsupported OS"),
...@@ -592,15 +558,15 @@ pub const CloseOperation = struct {...@@ -592,15 +558,15 @@ pub const CloseOperation = struct {
592558
593 pub fn getHandle(self: *CloseOperation) fd_t {559 pub fn getHandle(self: *CloseOperation) fd_t {
594 switch (builtin.os) {560 switch (builtin.os) {
595 builtin.Os.linux,561 .linux,
596 builtin.Os.macosx,562 .macosx,
597 builtin.Os.freebsd,563 .freebsd,
598 builtin.Os.netbsd,564 .netbsd,
599 => {565 => {
600 assert(self.os_data.have_fd);566 assert(self.os_data.have_fd);
601 return self.os_data.close_req_node.data.msg.Close.fd;567 return self.os_data.close_req_node.data.msg.Close.fd;
602 },568 },
603 builtin.Os.windows => {569 .windows => {
604 return self.os_data.handle.?;570 return self.os_data.handle.?;
605 },571 },
606 else => @compileError("Unsupported OS"),572 else => @compileError("Unsupported OS"),
...@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi...@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi
617/// contents must remain alive until writeFile completes.583/// contents must remain alive until writeFile completes.
618pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {584pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
619 switch (builtin.os) {585 switch (builtin.os) {
620 builtin.Os.linux,586 .linux,
621 builtin.Os.macosx,587 .macosx,
622 builtin.Os.freebsd,588 .freebsd,
623 builtin.Os.netbsd,589 .netbsd,
624 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),590 => 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),
626 else => @compileError("Unsupported OS"),592 else => @compileError("Unsupported OS"),
627 }593 }
628}594}
...@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !...@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !
643}609}
644610
645async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {611async 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
651 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);612 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);
652 defer loop.allocator.free(path_with_null);613 defer loop.allocator.free(path_with_null);
653614
...@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8...@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
667 .TickNode = Loop.NextTickNode{628 .TickNode = Loop.NextTickNode{
668 .prev = null,629 .prev = null,
669 .next = null,630 .next = null,
670 .data = @handle(),631 .data = @frame(),
671 },632 },
672 },633 },
673 },634 },
...@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8...@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
682 return req_node.data.msg.WriteFile.result;643 return req_node.data.msg.WriteFile.result;
683}644}
684645
685/// The promise resumes when the last data has been confirmed written, but before the file handle646/// The frame resumes when the last data has been confirmed written, but before the file handle
686/// is closed.647/// is closed.
687/// Caller owns returned memory.648/// Caller owns returned memory.
688pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {649pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {
...@@ -715,598 +676,583 @@ pub const WatchEventId = enum {...@@ -715,598 +676,583 @@ pub const WatchEventId = enum {
715 Delete,676 Delete,
716};677};
717678
718pub const WatchEventError = error{679//pub const WatchEventError = error{
719 UserResourceLimitReached,680// UserResourceLimitReached,
720 SystemResources,681// SystemResources,
721 AccessDenied,682// AccessDenied,
722 Unexpected, // TODO remove this possibility683// Unexpected, // TODO remove this possibility
723};684//};
724685//
725pub fn Watch(comptime V: type) type {686//pub fn Watch(comptime V: type) type {
726 return struct {687// return struct {
727 channel: *event.Channel(Event.Error!Event),688// channel: *event.Channel(Event.Error!Event),
728 os_data: OsData,689// os_data: OsData,
729690//
730 const OsData = switch (builtin.os) {691// const OsData = switch (builtin.os) {
731 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {692// .macosx, .freebsd, .netbsd => struct {
732 file_table: FileTable,693// file_table: FileTable,
733 table_lock: event.Lock,694// table_lock: event.Lock,
734695//
735 const FileTable = std.AutoHashMap([]const u8, *Put);696// const FileTable = std.AutoHashMap([]const u8, *Put);
736 const Put = struct {697// const Put = struct {
737 putter: promise,698// putter: anyframe,
738 value_ptr: *V,699// value_ptr: *V,
739 };700// };
740 },701// },
741702//
742 builtin.Os.linux => LinuxOsData,703// .linux => LinuxOsData,
743 builtin.Os.windows => WindowsOsData,704// .windows => WindowsOsData,
744705//
745 else => @compileError("Unsupported OS"),706// else => @compileError("Unsupported OS"),
746 };707// };
747708//
748 const WindowsOsData = struct {709// const WindowsOsData = struct {
749 table_lock: event.Lock,710// table_lock: event.Lock,
750 dir_table: DirTable,711// dir_table: DirTable,
751 all_putters: std.atomic.Queue(promise),712// all_putters: std.atomic.Queue(anyframe),
752 ref_count: std.atomic.Int(usize),713// ref_count: std.atomic.Int(usize),
753714//
754 const DirTable = std.AutoHashMap([]const u8, *Dir);715// const DirTable = std.AutoHashMap([]const u8, *Dir);
755 const FileTable = std.AutoHashMap([]const u16, V);716// const FileTable = std.AutoHashMap([]const u16, V);
756717//
757 const Dir = struct {718// const Dir = struct {
758 putter: promise,719// putter: anyframe,
759 file_table: FileTable,720// file_table: FileTable,
760 table_lock: event.Lock,721// table_lock: event.Lock,
761 };722// };
762 };723// };
763724//
764 const LinuxOsData = struct {725// const LinuxOsData = struct {
765 putter: promise,726// putter: anyframe,
766 inotify_fd: i32,727// inotify_fd: i32,
767 wd_table: WdTable,728// wd_table: WdTable,
768 table_lock: event.Lock,729// table_lock: event.Lock,
769730//
770 const WdTable = std.AutoHashMap(i32, Dir);731// const WdTable = std.AutoHashMap(i32, Dir);
771 const FileTable = std.AutoHashMap([]const u8, V);732// const FileTable = std.AutoHashMap([]const u8, V);
772733//
773 const Dir = struct {734// const Dir = struct {
774 dirname: []const u8,735// dirname: []const u8,
775 file_table: FileTable,736// file_table: FileTable,
776 };737// };
777 };738// };
778739//
779 const FileToHandle = std.AutoHashMap([]const u8, promise);740// const FileToHandle = std.AutoHashMap([]const u8, anyframe);
780741//
781 const Self = @This();742// const Self = @This();
782743//
783 pub const Event = struct {744// pub const Event = struct {
784 id: Id,745// id: Id,
785 data: V,746// data: V,
786747//
787 pub const Id = WatchEventId;748// pub const Id = WatchEventId;
788 pub const Error = WatchEventError;749// pub const Error = WatchEventError;
789 };750// };
790751//
791 pub fn create(loop: *Loop, event_buf_count: usize) !*Self {752// 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);753// const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
793 errdefer channel.destroy();754// errdefer channel.destroy();
794755//
795 switch (builtin.os) {756// switch (builtin.os) {
796 builtin.Os.linux => {757// .linux => {
797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);758// const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
798 errdefer os.close(inotify_fd);759// errdefer os.close(inotify_fd);
799760//
800 var result: *Self = undefined;761// var result: *Self = undefined;
801 _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);762// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
802 return result;763// return result;
803 },764// },
804765//
805 builtin.Os.windows => {766// .windows => {
806 const self = try loop.allocator.create(Self);767// const self = try loop.allocator.create(Self);
807 errdefer loop.allocator.destroy(self);768// errdefer loop.allocator.destroy(self);
808 self.* = Self{769// self.* = Self{
809 .channel = channel,770// .channel = channel,
810 .os_data = OsData{771// .os_data = OsData{
811 .table_lock = event.Lock.init(loop),772// .table_lock = event.Lock.init(loop),
812 .dir_table = OsData.DirTable.init(loop.allocator),773// .dir_table = OsData.DirTable.init(loop.allocator),
813 .ref_count = std.atomic.Int(usize).init(1),774// .ref_count = std.atomic.Int(usize).init(1),
814 .all_putters = std.atomic.Queue(promise).init(),775// .all_putters = std.atomic.Queue(anyframe).init(),
815 },776// },
816 };777// };
817 return self;778// return self;
818 },779// },
819780//
820 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {781// .macosx, .freebsd, .netbsd => {
821 const self = try loop.allocator.create(Self);782// const self = try loop.allocator.create(Self);
822 errdefer loop.allocator.destroy(self);783// errdefer loop.allocator.destroy(self);
823784//
824 self.* = Self{785// self.* = Self{
825 .channel = channel,786// .channel = channel,
826 .os_data = OsData{787// .os_data = OsData{
827 .table_lock = event.Lock.init(loop),788// .table_lock = event.Lock.init(loop),
828 .file_table = OsData.FileTable.init(loop.allocator),789// .file_table = OsData.FileTable.init(loop.allocator),
829 },790// },
830 };791// };
831 return self;792// return self;
832 },793// },
833 else => @compileError("Unsupported OS"),794// else => @compileError("Unsupported OS"),
834 }795// }
835 }796// }
836797//
837 /// All addFile calls and removeFile calls must have completed.798// /// All addFile calls and removeFile calls must have completed.
838 pub fn destroy(self: *Self) void {799// pub fn destroy(self: *Self) void {
839 switch (builtin.os) {800// switch (builtin.os) {
840 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {801// .macosx, .freebsd, .netbsd => {
841 // TODO we need to cancel the coroutines before destroying the lock802// // TODO we need to cancel the frames before destroying the lock
842 self.os_data.table_lock.deinit();803// self.os_data.table_lock.deinit();
843 var it = self.os_data.file_table.iterator();804// var it = self.os_data.file_table.iterator();
844 while (it.next()) |entry| {805// while (it.next()) |entry| {
845 cancel entry.value.putter;806// cancel entry.value.putter;
846 self.channel.loop.allocator.free(entry.key);807// self.channel.loop.allocator.free(entry.key);
847 }808// }
848 self.channel.destroy();809// self.channel.destroy();
849 },810// },
850 builtin.Os.linux => cancel self.os_data.putter,811// .linux => cancel self.os_data.putter,
851 builtin.Os.windows => {812// .windows => {
852 while (self.os_data.all_putters.get()) |putter_node| {813// while (self.os_data.all_putters.get()) |putter_node| {
853 cancel putter_node.data;814// cancel putter_node.data;
854 }815// }
855 self.deref();816// self.deref();
856 },817// },
857 else => @compileError("Unsupported OS"),818// else => @compileError("Unsupported OS"),
858 }819// }
859 }820// }
860821//
861 fn ref(self: *Self) void {822// fn ref(self: *Self) void {
862 _ = self.os_data.ref_count.incr();823// _ = self.os_data.ref_count.incr();
863 }824// }
864825//
865 fn deref(self: *Self) void {826// fn deref(self: *Self) void {
866 if (self.os_data.ref_count.decr() == 1) {827// if (self.os_data.ref_count.decr() == 1) {
867 const allocator = self.channel.loop.allocator;828// const allocator = self.channel.loop.allocator;
868 self.os_data.table_lock.deinit();829// self.os_data.table_lock.deinit();
869 var it = self.os_data.dir_table.iterator();830// var it = self.os_data.dir_table.iterator();
870 while (it.next()) |entry| {831// while (it.next()) |entry| {
871 allocator.free(entry.key);832// allocator.free(entry.key);
872 allocator.destroy(entry.value);833// allocator.destroy(entry.value);
873 }834// }
874 self.os_data.dir_table.deinit();835// self.os_data.dir_table.deinit();
875 self.channel.destroy();836// self.channel.destroy();
876 allocator.destroy(self);837// allocator.destroy(self);
877 }838// }
878 }839// }
879840//
880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {841// pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
881 switch (builtin.os) {842// switch (builtin.os) {
882 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),843// .macosx, .freebsd, .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),844// .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),845// .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),846// else => @compileError("Unsupported OS"),
886 }847// }
887 }848// }
888849//
889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {850// 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});851// const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891 var resolved_path_consumed = false;852// var resolved_path_consumed = false;
892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);853// defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893854//
894 var close_op = try CloseOperation.start(self.channel.loop);855// var close_op = try CloseOperation.start(self.channel.loop);
895 var close_op_consumed = false;856// var close_op_consumed = false;
896 defer if (!close_op_consumed) close_op.finish();857// defer if (!close_op_consumed) close_op.finish();
897858//
898 const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;859// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
899 const mode = 0;860// const mode = 0;
900 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);861// const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
901 close_op.setHandle(fd);862// close_op.setHandle(fd);
902863//
903 var put_data: *OsData.Put = undefined;864// var put_data: *OsData.Put = undefined;
904 const putter = try async self.kqPutEvents(close_op, value, &put_data);865// const putter = try async self.kqPutEvents(close_op, value, &put_data);
905 close_op_consumed = true;866// close_op_consumed = true;
906 errdefer cancel putter;867// errdefer cancel putter;
907868//
908 const result = blk: {869// const result = blk: {
909 const held = await (async self.os_data.table_lock.acquire() catch unreachable);870// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
910 defer held.release();871// defer held.release();
911872//
912 const gop = try self.os_data.file_table.getOrPut(resolved_path);873// const gop = try self.os_data.file_table.getOrPut(resolved_path);
913 if (gop.found_existing) {874// if (gop.found_existing) {
914 const prev_value = gop.kv.value.value_ptr.*;875// const prev_value = gop.kv.value.value_ptr.*;
915 cancel gop.kv.value.putter;876// cancel gop.kv.value.putter;
916 gop.kv.value = put_data;877// gop.kv.value = put_data;
917 break :blk prev_value;878// break :blk prev_value;
918 } else {879// } else {
919 resolved_path_consumed = true;880// resolved_path_consumed = true;
920 gop.kv.value = put_data;881// gop.kv.value = put_data;
921 break :blk null;882// break :blk null;
922 }883// }
923 };884// };
924885//
925 return result;886// return result;
926 }887// }
927888//
928 async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {889// async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
929 // TODO https://github.com/ziglang/zig/issues/1194890// var value_copy = value;
930 suspend {891// var put = OsData.Put{
931 resume @handle();892// .putter = @frame(),
932 }893// .value_ptr = &value_copy,
933894// };
934 var value_copy = value;895// out_put.* = &put;
935 var put = OsData.Put{896// self.channel.loop.beginOneEvent();
936 .putter = @handle(),897//
937 .value_ptr = &value_copy,898// defer {
938 };899// close_op.finish();
939 out_put.* = &put;900// self.channel.loop.finishOneEvent();
940 self.channel.loop.beginOneEvent();901// }
941902//
942 defer {903// while (true) {
943 close_op.finish();904// if (await (async self.channel.loop.bsdWaitKev(
944 self.channel.loop.finishOneEvent();905// @intCast(usize, close_op.getHandle()),
945 }906// os.EVFILT_VNODE,
946907// os.NOTE_WRITE | os.NOTE_DELETE,
947 while (true) {908// ) catch unreachable)) |kev| {
948 if (await (async self.channel.loop.bsdWaitKev(909// // TODO handle EV_ERROR
949 @intCast(usize, close_op.getHandle()),910// if (kev.fflags & os.NOTE_DELETE != 0) {
950 os.EVFILT_VNODE,911// await (async self.channel.put(Self.Event{
951 os.NOTE_WRITE | os.NOTE_DELETE,912// .id = Event.Id.Delete,
952 ) catch unreachable)) |kev| {913// .data = value_copy,
953 // TODO handle EV_ERROR914// }) catch unreachable);
954 if (kev.fflags & os.NOTE_DELETE != 0) {915// } else if (kev.fflags & os.NOTE_WRITE != 0) {
955 await (async self.channel.put(Self.Event{916// await (async self.channel.put(Self.Event{
956 .id = Event.Id.Delete,917// .id = Event.Id.CloseWrite,
957 .data = value_copy,918// .data = value_copy,
958 }) catch unreachable);919// }) catch unreachable);
959 } else if (kev.fflags & os.NOTE_WRITE != 0) {920// }
960 await (async self.channel.put(Self.Event{921// } else |err| switch (err) {
961 .id = Event.Id.CloseWrite,922// error.EventNotFound => unreachable,
962 .data = value_copy,923// error.ProcessNotFound => unreachable,
963 }) catch unreachable);924// error.Overflow => unreachable,
964 }925// error.AccessDenied, error.SystemResources => |casted_err| {
965 } else |err| switch (err) {926// await (async self.channel.put(casted_err) catch unreachable);
966 error.EventNotFound => unreachable,927// },
967 error.ProcessNotFound => unreachable,928// }
968 error.Overflow => unreachable,929// }
969 error.AccessDenied, error.SystemResources => |casted_err| {930// }
970 await (async self.channel.put(casted_err) catch unreachable);931//
971 },932// async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
972 }933// const value_copy = value;
973 }934//
974 }935// const dirname = std.fs.path.dirname(file_path) orelse ".";
975936// const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {937// var dirname_with_null_consumed = false;
977 const value_copy = value;938// defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
978939//
979 const dirname = std.fs.path.dirname(file_path) orelse ".";940// const basename = std.fs.path.basename(file_path);
980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);941// const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
981 var dirname_with_null_consumed = false;942// var basename_with_null_consumed = false;
982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);943// defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
983944//
984 const basename = std.fs.path.basename(file_path);945// const wd = try os.inotify_add_watchC(
985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);946// self.os_data.inotify_fd,
986 var basename_with_null_consumed = false;947// dirname_with_null.ptr,
987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);948// os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
988949// );
989 const wd = try os.inotify_add_watchC(950// // wd is either a newly created watch or an existing one.
990 self.os_data.inotify_fd,951//
991 dirname_with_null.ptr,952// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
992 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,953// defer held.release();
993 );954//
994 // wd is either a newly created watch or an existing one.955// const gop = try self.os_data.wd_table.getOrPut(wd);
995956// if (!gop.found_existing) {
996 const held = await (async self.os_data.table_lock.acquire() catch unreachable);957// gop.kv.value = OsData.Dir{
997 defer held.release();958// .dirname = dirname_with_null,
998959// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
999 const gop = try self.os_data.wd_table.getOrPut(wd);960// };
1000 if (!gop.found_existing) {961// dirname_with_null_consumed = true;
1001 gop.kv.value = OsData.Dir{962// }
1002 .dirname = dirname_with_null,963// const dir = &gop.kv.value;
1003 .file_table = OsData.FileTable.init(self.channel.loop.allocator),964//
1004 };965// const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
1005 dirname_with_null_consumed = true;966// if (file_table_gop.found_existing) {
1006 }967// const prev_value = file_table_gop.kv.value;
1007 const dir = &gop.kv.value;968// file_table_gop.kv.value = value_copy;
1008969// return prev_value;
1009 const file_table_gop = try dir.file_table.getOrPut(basename_with_null);970// } else {
1010 if (file_table_gop.found_existing) {971// file_table_gop.kv.value = value_copy;
1011 const prev_value = file_table_gop.kv.value;972// basename_with_null_consumed = true;
1012 file_table_gop.kv.value = value_copy;973// return null;
1013 return prev_value;974// }
1014 } else {975// }
1015 file_table_gop.kv.value = value_copy;976//
1016 basename_with_null_consumed = true;977// async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
1017 return null;978// const value_copy = value;
1018 }979// // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
1019 }980//
1020981// const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1021 async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {982// var dirname_consumed = false;
1022 const value_copy = value;983// defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)984//
1024985// const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");986// defer self.channel.loop.allocator.free(dirname_utf16le);
1026 var dirname_consumed = false;987//
1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);988// // TODO https://github.com/ziglang/zig/issues/265
1028989// const basename = std.fs.path.basename(file_path);
1029 const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);990// const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1030 defer self.channel.loop.allocator.free(dirname_utf16le);991// var basename_utf16le_null_consumed = false;
1031992// defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1032 // TODO https://github.com/ziglang/zig/issues/265993// const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
1033 const basename = std.fs.path.basename(file_path);994//
1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);995// const dir_handle = try windows.CreateFileW(
1035 var basename_utf16le_null_consumed = false;996// dirname_utf16le.ptr,
1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);997// windows.FILE_LIST_DIRECTORY,
1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];998// windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
1038999// null,
1039 const dir_handle = try windows.CreateFileW(1000// windows.OPEN_EXISTING,
1040 dirname_utf16le.ptr,1001// windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1041 windows.FILE_LIST_DIRECTORY,1002// null,
1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,1003// );
1043 null,1004// var dir_handle_consumed = false;
1044 windows.OPEN_EXISTING,1005// defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,1006//
1046 null,1007// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1047 );1008// defer held.release();
1048 var dir_handle_consumed = false;1009//
1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);1010// const gop = try self.os_data.dir_table.getOrPut(dirname);
10501011// if (gop.found_existing) {
1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);1012// const dir = gop.kv.value;
1052 defer held.release();1013// const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
10531014// defer held_dir_lock.release();
1054 const gop = try self.os_data.dir_table.getOrPut(dirname);1015//
1055 if (gop.found_existing) {1016// const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1056 const dir = gop.kv.value;1017// if (file_gop.found_existing) {
1057 const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);1018// const prev_value = file_gop.kv.value;
1058 defer held_dir_lock.release();1019// file_gop.kv.value = value_copy;
10591020// return prev_value;
1060 const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);1021// } else {
1061 if (file_gop.found_existing) {1022// file_gop.kv.value = value_copy;
1062 const prev_value = file_gop.kv.value;1023// basename_utf16le_null_consumed = true;
1063 file_gop.kv.value = value_copy;1024// return null;
1064 return prev_value;1025// }
1065 } else {1026// } else {
1066 file_gop.kv.value = value_copy;1027// errdefer _ = self.os_data.dir_table.remove(dirname);
1067 basename_utf16le_null_consumed = true;1028// const dir = try self.channel.loop.allocator.create(OsData.Dir);
1068 return null;1029// errdefer self.channel.loop.allocator.destroy(dir);
1069 }1030//
1070 } else {1031// dir.* = OsData.Dir{
1071 errdefer _ = self.os_data.dir_table.remove(dirname);1032// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1072 const dir = try self.channel.loop.allocator.create(OsData.Dir);1033// .table_lock = event.Lock.init(self.channel.loop),
1073 errdefer self.channel.loop.allocator.destroy(dir);1034// .putter = undefined,
10741035// };
1075 dir.* = OsData.Dir{1036// gop.kv.value = dir;
1076 .file_table = OsData.FileTable.init(self.channel.loop.allocator),1037// assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1077 .table_lock = event.Lock.init(self.channel.loop),1038// basename_utf16le_null_consumed = true;
1078 .putter = undefined,1039//
1079 };1040// dir.putter = try async self.windowsDirReader(dir_handle, dir);
1080 gop.kv.value = dir;1041// dir_handle_consumed = true;
1081 assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);1042//
1082 basename_utf16le_null_consumed = true;1043// dirname_consumed = true;
10831044//
1084 dir.putter = try async self.windowsDirReader(dir_handle, dir);1045// return null;
1085 dir_handle_consumed = true;1046// }
10861047// }
1087 dirname_consumed = true;1048//
10881049// async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1089 return null;1050// self.ref();
1090 }1051// defer self.deref();
1091 }1052//
10921053// defer os.close(dir_handle);
1093 async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {1054//
1094 // TODO https://github.com/ziglang/zig/issues/11941055// var putter_node = std.atomic.Queue(anyframe).Node{
1095 suspend {1056// .data = @frame(),
1096 resume @handle();1057// .prev = null,
1097 }1058// .next = null,
10981059// };
1099 self.ref();1060// self.os_data.all_putters.put(&putter_node);
1100 defer self.deref();1061// defer _ = self.os_data.all_putters.remove(&putter_node);
11011062//
1102 defer os.close(dir_handle);1063// var resume_node = Loop.ResumeNode.Basic{
11031064// .base = Loop.ResumeNode{
1104 var putter_node = std.atomic.Queue(promise).Node{1065// .id = Loop.ResumeNode.Id.Basic,
1105 .data = @handle(),1066// .handle = @frame(),
1106 .prev = null,1067// .overlapped = windows.OVERLAPPED{
1107 .next = null,1068// .Internal = 0,
1108 };1069// .InternalHigh = 0,
1109 self.os_data.all_putters.put(&putter_node);1070// .Offset = 0,
1110 defer _ = self.os_data.all_putters.remove(&putter_node);1071// .OffsetHigh = 0,
11111072// .hEvent = null,
1112 var resume_node = Loop.ResumeNode.Basic{1073// },
1113 .base = Loop.ResumeNode{1074// },
1114 .id = Loop.ResumeNode.Id.Basic,1075// };
1115 .handle = @handle(),1076// var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1116 .overlapped = windows.OVERLAPPED{1077//
1117 .Internal = 0,1078// // TODO handle this error not in the channel but in the setup
1118 .InternalHigh = 0,1079// _ = windows.CreateIoCompletionPort(
1119 .Offset = 0,1080// dir_handle,
1120 .OffsetHigh = 0,1081// self.channel.loop.os_data.io_port,
1121 .hEvent = null,1082// undefined,
1122 },1083// undefined,
1123 },1084// ) catch |err| {
1124 };1085// await (async self.channel.put(err) catch unreachable);
1125 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;1086// return;
11261087// };
1127 // TODO handle this error not in the channel but in the setup1088//
1128 _ = windows.CreateIoCompletionPort(1089// while (true) {
1129 dir_handle,1090// {
1130 self.channel.loop.os_data.io_port,1091// // TODO only 1 beginOneEvent for the whole function
1131 undefined,1092// self.channel.loop.beginOneEvent();
1132 undefined,1093// errdefer self.channel.loop.finishOneEvent();
1133 ) catch |err| {1094// errdefer {
1134 await (async self.channel.put(err) catch unreachable);1095// _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1135 return;1096// }
1136 };1097// suspend {
11371098// _ = windows.kernel32.ReadDirectoryChangesW(
1138 while (true) {1099// dir_handle,
1139 {1100// &event_buf,
1140 // TODO only 1 beginOneEvent for the whole coroutine1101// @intCast(windows.DWORD, event_buf.len),
1141 self.channel.loop.beginOneEvent();1102// windows.FALSE, // watch subtree
1142 errdefer self.channel.loop.finishOneEvent();1103// windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1143 errdefer {1104// windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1144 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);1105// windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1145 }1106// windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1146 suspend {1107// null, // number of bytes transferred (unused for async)
1147 _ = windows.kernel32.ReadDirectoryChangesW(1108// &resume_node.base.overlapped,
1148 dir_handle,1109// null, // completion routine - unused because we use IOCP
1149 &event_buf,1110// );
1150 @intCast(windows.DWORD, event_buf.len),1111// }
1151 windows.FALSE, // watch subtree1112// }
1152 windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |1113// var bytes_transferred: windows.DWORD = undefined;
1153 windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |1114// if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1154 windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |1115// const err = switch (windows.kernel32.GetLastError()) {
1155 windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,1116// else => |err| windows.unexpectedError(err),
1156 null, // number of bytes transferred (unused for async)1117// };
1157 &resume_node.base.overlapped,1118// await (async self.channel.put(err) catch unreachable);
1158 null, // completion routine - unused because we use IOCP1119// } else {
1159 );1120// // can't use @bytesToSlice because of the special variable length name field
1160 }1121// var ptr = event_buf[0..].ptr;
1161 }1122// const end_ptr = ptr + bytes_transferred;
1162 var bytes_transferred: windows.DWORD = undefined;1123// var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1163 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {1124// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1164 const err = switch (windows.kernel32.GetLastError()) {1125// ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1165 else => |err| windows.unexpectedError(err),1126// const emit = switch (ev.Action) {
1166 };1127// windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1167 await (async self.channel.put(err) catch unreachable);1128// windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1168 } else {1129// else => null,
1169 // can't use @bytesToSlice because of the special variable length name field1130// };
1170 var ptr = event_buf[0..].ptr;1131// if (emit) |id| {
1171 const end_ptr = ptr + bytes_transferred;1132// const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1172 var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;1133// const user_value = blk: {
1173 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {1134// const held = await (async dir.table_lock.acquire() catch unreachable);
1174 ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);1135// defer held.release();
1175 const emit = switch (ev.Action) {1136//
1176 windows.FILE_ACTION_REMOVED => WatchEventId.Delete,1137// if (dir.file_table.get(basename_utf16le)) |entry| {
1177 windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,1138// break :blk entry.value;
1178 else => null,1139// } else {
1179 };1140// break :blk null;
1180 if (emit) |id| {1141// }
1181 const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];1142// };
1182 const user_value = blk: {1143// if (user_value) |v| {
1183 const held = await (async dir.table_lock.acquire() catch unreachable);1144// await (async self.channel.put(Event{
1184 defer held.release();1145// .id = id,
11851146// .data = v,
1186 if (dir.file_table.get(basename_utf16le)) |entry| {1147// }) catch unreachable);
1187 break :blk entry.value;1148// }
1188 } else {1149// }
1189 break :blk null;1150// if (ev.NextEntryOffset == 0) break;
1190 }1151// }
1191 };1152// }
1192 if (user_value) |v| {1153// }
1193 await (async self.channel.put(Event{1154// }
1194 .id = id,1155//
1195 .data = v,1156// pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1196 }) catch unreachable);1157// @panic("TODO");
1197 }1158// }
1198 }1159//
1199 if (ev.NextEntryOffset == 0) break;1160// async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1200 }1161// const loop = channel.loop;
1201 }1162//
1202 }1163// var watch = Self{
1203 }1164// .channel = channel,
12041165// .os_data = OsData{
1205 pub async fn removeFile(self: *Self, file_path: []const u8) ?V {1166// .putter = @frame(),
1206 @panic("TODO");1167// .inotify_fd = inotify_fd,
1207 }1168// .wd_table = OsData.WdTable.init(loop.allocator),
12081169// .table_lock = event.Lock.init(loop),
1209 async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {1170// },
1210 // TODO https://github.com/ziglang/zig/issues/11941171// };
1211 suspend {1172// out_watch.* = &watch;
1212 resume @handle();1173//
1213 }1174// loop.beginOneEvent();
12141175//
1215 const loop = channel.loop;1176// defer {
12161177// watch.os_data.table_lock.deinit();
1217 var watch = Self{1178// var wd_it = watch.os_data.wd_table.iterator();
1218 .channel = channel,1179// while (wd_it.next()) |wd_entry| {
1219 .os_data = OsData{1180// var file_it = wd_entry.value.file_table.iterator();
1220 .putter = @handle(),1181// while (file_it.next()) |file_entry| {
1221 .inotify_fd = inotify_fd,1182// loop.allocator.free(file_entry.key);
1222 .wd_table = OsData.WdTable.init(loop.allocator),1183// }
1223 .table_lock = event.Lock.init(loop),1184// loop.allocator.free(wd_entry.value.dirname);
1224 },1185// }
1225 };1186// loop.finishOneEvent();
1226 out_watch.* = &watch;1187// os.close(inotify_fd);
12271188// channel.destroy();
1228 loop.beginOneEvent();1189// }
12291190//
1230 defer {1191// var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1231 watch.os_data.table_lock.deinit();1192//
1232 var wd_it = watch.os_data.wd_table.iterator();1193// while (true) {
1233 while (wd_it.next()) |wd_entry| {1194// const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1234 var file_it = wd_entry.value.file_table.iterator();1195// const errno = os.linux.getErrno(rc);
1235 while (file_it.next()) |file_entry| {1196// switch (errno) {
1236 loop.allocator.free(file_entry.key);1197// 0 => {
1237 }1198// // can't use @bytesToSlice because of the special variable length name field
1238 loop.allocator.free(wd_entry.value.dirname);1199// var ptr = event_buf[0..].ptr;
1239 }1200// const end_ptr = ptr + event_buf.len;
1240 loop.finishOneEvent();1201// var ev: *os.linux.inotify_event = undefined;
1241 os.close(inotify_fd);1202// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1242 channel.destroy();1203// ev = @ptrCast(*os.linux.inotify_event, ptr);
1243 }1204// if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
12441205// const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1245 var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;1206// const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
12461207// const user_value = blk: {
1247 while (true) {1208// const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1248 const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);1209// defer held.release();
1249 const errno = os.linux.getErrno(rc);1210//
1250 switch (errno) {1211// const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1251 0 => {1212// if (dir.file_table.get(basename_with_null)) |entry| {
1252 // can't use @bytesToSlice because of the special variable length name field1213// break :blk entry.value;
1253 var ptr = event_buf[0..].ptr;1214// } else {
1254 const end_ptr = ptr + event_buf.len;1215// break :blk null;
1255 var ev: *os.linux.inotify_event = undefined;1216// }
1256 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {1217// };
1257 ev = @ptrCast(*os.linux.inotify_event, ptr);1218// if (user_value) |v| {
1258 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {1219// await (async channel.put(Event{
1259 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);1220// .id = WatchEventId.CloseWrite,
1260 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];1221// .data = v,
1261 const user_value = blk: {1222// }) catch unreachable);
1262 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);1223// }
1263 defer held.release();1224// }
12641225// }
1265 const dir = &watch.os_data.wd_table.get(ev.wd).?.value;1226// },
1266 if (dir.file_table.get(basename_with_null)) |entry| {1227// os.linux.EINTR => continue,
1267 break :blk entry.value;1228// os.linux.EINVAL => unreachable,
1268 } else {1229// os.linux.EFAULT => unreachable,
1269 break :blk null;1230// os.linux.EAGAIN => {
1270 }1231// (await (async loop.linuxWaitFd(
1271 };1232// inotify_fd,
1272 if (user_value) |v| {1233// os.linux.EPOLLET | os.linux.EPOLLIN,
1273 await (async channel.put(Event{1234// ) catch unreachable)) catch |err| {
1274 .id = WatchEventId.CloseWrite,1235// const transformed_err = switch (err) {
1275 .data = v,1236// error.FileDescriptorAlreadyPresentInSet => unreachable,
1276 }) catch unreachable);1237// error.OperationCausesCircularLoop => unreachable,
1277 }1238// error.FileDescriptorNotRegistered => unreachable,
1278 }1239// error.FileDescriptorIncompatibleWithEpoll => unreachable,
1279 }1240// error.Unexpected => unreachable,
1280 },1241// else => |e| e,
1281 os.linux.EINTR => continue,1242// };
1282 os.linux.EINVAL => unreachable,1243// await (async channel.put(transformed_err) catch unreachable);
1283 os.linux.EFAULT => unreachable,1244// };
1284 os.linux.EAGAIN => {1245// },
1285 (await (async loop.linuxWaitFd(1246// else => unreachable,
1286 inotify_fd,1247// }
1287 os.linux.EPOLLET | os.linux.EPOLLIN,1248// }
1288 ) catch unreachable)) catch |err| {1249// }
1289 const transformed_err = switch (err) {1250// };
1290 error.FileDescriptorAlreadyPresentInSet => unreachable,1251//}
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}
13061252
1307const test_tmp_dir = "std_event_fs_test";1253const 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.
1310//test "write a file, watch it, write it again" {1256//test "write a file, watch it, write it again" {
1311// return error.SkipZigTest;1257// return error.SkipZigTest;
1312// const allocator = std.heap.direct_allocator;1258// const allocator = std.heap.direct_allocator;
...@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {...@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {
13551301
1356 const ev = try async watch.channel.get();1302 const ev = try async watch.channel.get();
1357 var ev_consumed = false;1303 var ev_consumed = false;
1358 defer if (!ev_consumed) cancel ev;1304 defer if (!ev_consumed) await ev;
13591305
1360 // overwrite line 21306 // overwrite line 2
1361 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);1307 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
...@@ -1397,11 +1343,11 @@ pub const OutStream = struct {...@@ -1397,11 +1343,11 @@ pub const OutStream = struct {
1397 };1343 };
1398 }1344 }
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 {
1401 const self = @fieldParentPtr(OutStream, "stream", out_stream);1347 const self = @fieldParentPtr(OutStream, "stream", out_stream);
1402 const offset = self.offset;1348 const offset = self.offset;
1403 self.offset += bytes.len;1349 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);
1405 }1351 }
1406};1352};
14071353
...@@ -1423,9 +1369,9 @@ pub const InStream = struct {...@@ -1423,9 +1369,9 @@ pub const InStream = struct {
1423 };1369 };
1424 }1370 }
14251371
1426 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {1372 fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
1427 const self = @fieldParentPtr(InStream, "stream", in_stream);1373 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);
1429 self.offset += amt;1375 self.offset += amt;
1430 return amt;1376 return amt;
1431 }1377 }
std/event/future.zig+21-28
...@@ -2,13 +2,11 @@ const std = @import("../std.zig");...@@ -2,13 +2,11 @@ const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const Lock = std.event.Lock;5const Lock = std.event.Lock;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// This is a value that starts out unavailable, until resolve() is called8/// 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,
12/// and then are resumed when resolve() is called.10/// and then are resumed when resolve() is called.
13/// At this point the value remains forever available, and another resolve() is not allowed.11/// At this point the value remains forever available, and another resolve() is not allowed.
14pub fn Future(comptime T: type) type {12pub fn Future(comptime T: type) type {
...@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {...@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {
23 available: u8,21 available: u8,
2422
25 const Self = @This();23 const Self = @This();
26 const Queue = std.atomic.Queue(promise);24 const Queue = std.atomic.Queue(anyframe);
2725
28 pub fn init(loop: *Loop) Self {26 pub fn init(loop: *Loop) Self {
29 return Self{27 return Self{
...@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {...@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {
37 /// available.35 /// available.
38 /// Thread-safe.36 /// Thread-safe.
39 pub async fn get(self: *Self) *T {37 pub async fn get(self: *Self) *T {
40 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {38 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
41 return &self.data;39 return &self.data;
42 }40 }
43 const held = await (async self.lock.acquire() catch unreachable);41 const held = self.lock.acquire();
44 held.release();42 held.release();
4543
46 return &self.data;44 return &self.data;
...@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {...@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {
49 /// Gets the data without waiting for it. If it's available, a pointer is47 /// Gets the data without waiting for it. If it's available, a pointer is
50 /// returned. Otherwise, null is returned.48 /// returned. Otherwise, null is returned.
51 pub fn getOrNull(self: *Self) ?*T {49 pub fn getOrNull(self: *Self) ?*T {
52 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {50 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
53 return &self.data;51 return &self.data;
54 } else {52 } else {
55 return null;53 return null;
...@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {...@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {
62 /// It's not required to call start() before resolve() but it can be useful since60 /// It's not required to call start() before resolve() but it can be useful since
63 /// this method is thread-safe.61 /// this method is thread-safe.
64 pub async fn start(self: *Self) ?*T {62 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;
66 switch (state) {64 switch (state) {
67 1 => {65 1 => {
68 const held = await (async self.lock.acquire() catch unreachable);66 const held = self.lock.acquire();
69 held.release();67 held.release();
70 return &self.data;68 return &self.data;
71 },69 },
...@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {...@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {
77 /// Make the data become available. May be called only once.75 /// Make the data become available. May be called only once.
78 /// Before calling this, modify the `data` property.76 /// Before calling this, modify the `data` property.
79 pub fn resolve(self: *Self) void {77 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);
81 assert(prev == 0 or prev == 1); // resolve() called twice79 assert(prev == 0 or prev == 1); // resolve() called twice
82 Lock.Held.release(Lock.Held{ .lock = &self.lock });80 Lock.Held.release(Lock.Held{ .lock = &self.lock });
83 }81 }
...@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {...@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {
8684
87test "std.event.Future" {85test "std.event.Future" {
88 // https://github.com/ziglang/zig/issues/190886 // 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
91 const allocator = std.heap.direct_allocator;89 const allocator = std.heap.direct_allocator;
9290
...@@ -94,38 +92,33 @@ test "std.event.Future" {...@@ -94,38 +92,33 @@ test "std.event.Future" {
94 try loop.initMultiThreaded(allocator);92 try loop.initMultiThreaded(allocator);
95 defer loop.deinit();93 defer loop.deinit();
9694
97 const handle = try async<allocator> testFuture(&loop);95 const handle = async testFuture(&loop);
98 defer cancel handle;
9996
100 loop.run();97 loop.run();
101}98}
10299
103async fn testFuture(loop: *Loop) void {100async fn testFuture(loop: *Loop) void {
104 suspend {
105 resume @handle();
106 }
107 var future = Future(i32).init(loop);101 var future = Future(i32).init(loop);
108102
109 const a = async waitOnFuture(&future) catch @panic("memory");103 const a = async waitOnFuture(&future);
110 const b = async waitOnFuture(&future) catch @panic("memory");104 const b = async waitOnFuture(&future);
111 const c = async resolveFuture(&future) catch @panic("memory");105 const c = async resolveFuture(&future);
112106
113 const result = (await a) + (await b);107 // TODO make this work:
114 cancel c;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;
115 testing.expect(result == 12);114 testing.expect(result == 12);
116}115}
117116
118async fn waitOnFuture(future: *Future(i32)) i32 {117async fn waitOnFuture(future: *Future(i32)) i32 {
119 suspend {118 return future.get().*;
120 resume @handle();
121 }
122 return (await (async future.get() catch @panic("memory"))).*;
123}119}
124120
125async fn resolveFuture(future: *Future(i32)) void {121async fn resolveFuture(future: *Future(i32)) void {
126 suspend {
127 resume @handle();
128 }
129 future.data = 6;122 future.data = 6;
130 future.resolve();123 future.resolve();
131}124}
std/event/group.zig+29-67
...@@ -2,46 +2,33 @@ const std = @import("../std.zig");...@@ -2,46 +2,33 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Lock = std.event.Lock;3const Lock = std.event.Lock;
4const Loop = std.event.Loop;4const Loop = std.event.Loop;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const testing = std.testing;5const testing = std.testing;
86
9/// ReturnType must be `void` or `E!void`7/// ReturnType must be `void` or `E!void`
10pub fn Group(comptime ReturnType: type) type {8pub fn Group(comptime ReturnType: type) type {
11 return struct {9 return struct {
12 coro_stack: Stack,10 frame_stack: Stack,
13 alloc_stack: Stack,11 alloc_stack: Stack,
14 lock: Lock,12 lock: Lock,
1513
16 const Self = @This();14 const Self = @This();
1715
18 const Error = switch (@typeInfo(ReturnType)) {16 const Error = switch (@typeInfo(ReturnType)) {
19 builtin.TypeId.ErrorUnion => |payload| payload.error_set,17 .ErrorUnion => |payload| payload.error_set,
20 else => void,18 else => void,
21 };19 };
22 const Stack = std.atomic.Stack(promise->ReturnType);20 const Stack = std.atomic.Stack(anyframe->ReturnType);
2321
24 pub fn init(loop: *Loop) Self {22 pub fn init(loop: *Loop) Self {
25 return Self{23 return Self{
26 .coro_stack = Stack.init(),24 .frame_stack = Stack.init(),
27 .alloc_stack = Stack.init(),25 .alloc_stack = Stack.init(),
28 .lock = Lock.init(loop),26 .lock = Lock.init(loop),
29 };27 };
30 }28 }
3129
32 /// Cancel all the outstanding promises. Can be called even if wait was already called.30 /// Add a frame to the group. Thread-safe.
33 pub fn deinit(self: *Self) void {31 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!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) {
45 const node = try self.lock.loop.allocator.create(Stack.Node);32 const node = try self.lock.loop.allocator.create(Stack.Node);
46 node.* = Stack.Node{33 node.* = Stack.Node{
47 .next = undefined,34 .next = undefined,
...@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {...@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {
51 }38 }
5239
53 /// Add a node to the group. Thread-safe. Cannot fail.40 /// Add a node to the group. Thread-safe. Cannot fail.
54 /// `node.data` should be the promise handle to add to the group.41 /// `node.data` should be the frame handle to add to the group.
55 /// The node's memory should be in the coroutine frame of42 /// The node's memory should be in the function frame of
56 /// the handle that is in the node, or somewhere guaranteed to live43 /// the handle that is in the node, or somewhere guaranteed to live
57 /// at least as long.44 /// at least as long.
58 pub fn addNode(self: *Self, node: *Stack.Node) void {45 pub fn addNode(self: *Self, node: *Stack.Node) void {
59 self.coro_stack.push(node);46 self.frame_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);
87 }47 }
8848
89 /// Wait for all the calls and promises of the group to complete.49 /// Wait for all the calls and promises of the group to complete.
90 /// Thread-safe.50 /// Thread-safe.
91 /// Safe to call any number of times.51 /// Safe to call any number of times.
92 pub async fn wait(self: *Self) ReturnType {52 pub async fn wait(self: *Self) ReturnType {
93 // TODO catch unreachable because the allocation can be grouped with53 const held = self.lock.acquire();
94 // the coro frame allocation
95 const held = await (async self.lock.acquire() catch unreachable);
96 defer held.release();54 defer held.release();
9755
98 while (self.coro_stack.pop()) |node| {56 var result: ReturnType = {};
57
58 while (self.frame_stack.pop()) |node| {
99 if (Error == void) {59 if (Error == void) {
100 await node.data;60 await node.data;
101 } else {61 } else {
102 (await node.data) catch |err| {62 (await node.data) catch |err| {
103 self.deinit();63 result = err;
104 return err;
105 };64 };
106 }65 }
107 }66 }
...@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {...@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {
112 await handle;71 await handle;
113 } else {72 } else {
114 (await handle) catch |err| {73 (await handle) catch |err| {
115 self.deinit();74 result = err;
116 return err;
117 };75 };
118 }76 }
119 }77 }
78 return result;
120 }79 }
121 };80 };
122}81}
...@@ -131,8 +90,7 @@ test "std.event.Group" {...@@ -131,8 +90,7 @@ test "std.event.Group" {
131 try loop.initMultiThreaded(allocator);90 try loop.initMultiThreaded(allocator);
132 defer loop.deinit();91 defer loop.deinit();
13392
134 const handle = try async<allocator> testGroup(&loop);93 const handle = async testGroup(&loop);
135 defer cancel handle;
13694
137 loop.run();95 loop.run();
138}96}
...@@ -140,26 +98,30 @@ test "std.event.Group" {...@@ -140,26 +98,30 @@ test "std.event.Group" {
140async fn testGroup(loop: *Loop) void {98async fn testGroup(loop: *Loop) void {
141 var count: usize = 0;99 var count: usize = 0;
142 var group = Group(void).init(loop);100 var group = Group(void).init(loop);
143 group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");101 var sleep_a_little_frame = async sleepALittle(&count);
144 group.call(increaseByTen, &count) catch @panic("memory");102 group.add(&sleep_a_little_frame) catch @panic("memory");
145 await (async group.wait() 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();
146 testing.expect(count == 11);106 testing.expect(count == 11);
147107
148 var another = Group(anyerror!void).init(loop);108 var another = Group(anyerror!void).init(loop);
149 another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");109 var something_else_frame = async somethingElse();
150 another.call(doSomethingThatFails) catch @panic("memory");110 another.add(&something_else_frame) catch @panic("memory");
151 testing.expectError(error.ItBroke, await (async another.wait() 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());
152}114}
153115
154async fn sleepALittle(count: *usize) void {116async fn sleepALittle(count: *usize) void {
155 std.time.sleep(1 * std.time.millisecond);117 std.time.sleep(1 * std.time.millisecond);
156 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);118 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
157}119}
158120
159async fn increaseByTen(count: *usize) void {121async fn increaseByTen(count: *usize) void {
160 var i: usize = 0;122 var i: usize = 0;
161 while (i < 10) : (i += 1) {123 while (i < 10) : (i += 1) {
162 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);124 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
163 }125 }
164}126}
165127
std/event/io.zig+9-10
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;3const assert = std.debug.assert;
5const mem = std.mem;4const mem = std.mem;
65
...@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {...@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {
12 /// Return the number of bytes read. It may be less than buffer.len.11 /// Return the number of bytes read. It may be less than buffer.len.
13 /// If the number of bytes read is 0, it means end of stream.12 /// If the number of bytes read is 0, it means end of stream.
14 /// End of stream is not an error condition.13 /// 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
17 /// Return the number of bytes read. It may be less than buffer.len.16 /// Return the number of bytes read. It may be less than buffer.len.
18 /// If the number of bytes read is 0, it means end of stream.17 /// If the number of bytes read is 0, it means end of stream.
19 /// End of stream is not an error condition.18 /// End of stream is not an error condition.
20 pub async fn read(self: *Self, buffer: []u8) !usize {19 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);
22 }21 }
2322
24 /// Return the number of bytes read. If it is less than buffer.len23 /// Return the number of bytes read. If it is less than buffer.len
...@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {
26 pub async fn readFull(self: *Self, buffer: []u8) !usize {25 pub async fn readFull(self: *Self, buffer: []u8) !usize {
27 var index: usize = 0;26 var index: usize = 0;
28 while (index != buf.len) {27 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..]);
30 if (amt_read == 0) return index;29 if (amt_read == 0) return index;
31 index += amt_read;30 index += amt_read;
32 }31 }
...@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {...@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {
3534
36 /// Same as `readFull` but end of stream returns `error.EndOfStream`.35 /// Same as `readFull` but end of stream returns `error.EndOfStream`.
37 pub async fn readNoEof(self: *Self, buf: []u8) !void {36 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..]);
39 if (amt_read < buf.len) return error.EndOfStream;38 if (amt_read < buf.len) return error.EndOfStream;
40 }39 }
4140
42 pub async fn readIntLittle(self: *Self, comptime T: type) !T {41 pub async fn readIntLittle(self: *Self, comptime T: type) !T {
43 var bytes: [@sizeOf(T)]u8 = undefined;42 var bytes: [@sizeOf(T)]u8 = undefined;
44 try await (async self.readNoEof(bytes[0..]) catch unreachable);43 try self.readNoEof(bytes[0..]);
45 return mem.readIntLittle(T, &bytes);44 return mem.readIntLittle(T, &bytes);
46 }45 }
4746
48 pub async fn readIntBe(self: *Self, comptime T: type) !T {47 pub async fn readIntBe(self: *Self, comptime T: type) !T {
49 var bytes: [@sizeOf(T)]u8 = undefined;48 var bytes: [@sizeOf(T)]u8 = undefined;
50 try await (async self.readNoEof(bytes[0..]) catch unreachable);49 try self.readNoEof(bytes[0..]);
51 return mem.readIntBig(T, &bytes);50 return mem.readIntBig(T, &bytes);
52 }51 }
5352
54 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {53 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
55 var bytes: [@sizeOf(T)]u8 = undefined;54 var bytes: [@sizeOf(T)]u8 = undefined;
56 try await (async self.readNoEof(bytes[0..]) catch unreachable);55 try self.readNoEof(bytes[0..]);
57 return mem.readInt(T, &bytes, endian);56 return mem.readInt(T, &bytes, endian);
58 }57 }
5958
...@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {
61 // Only extern and packed structs have defined in-memory layout.60 // Only extern and packed structs have defined in-memory layout.
62 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);61 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
63 var res: [1]T = undefined;62 var res: [1]T = undefined;
64 try await (async self.readNoEof(@sliceToBytes(res[0..])) catch unreachable);63 try self.readNoEof(@sliceToBytes(res[0..]));
65 return res[0];64 return res[0];
66 }65 }
67 };66 };
...@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {...@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {
72 const Self = @This();71 const Self = @This();
73 pub const Error = WriteError;72 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,
76 };75 };
77}76}
std/event/lock.zig+23-36
...@@ -3,12 +3,10 @@ const builtin = @import("builtin");...@@ -3,12 +3,10 @@ const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// Thread-safe async/await lock.8/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and9/// Functions which are waiting for the lock are suspended, and
12/// are resumed when the lock is released, in order.10/// are resumed when the lock is released, in order.
13/// Allows only one actor to hold the lock.11/// Allows only one actor to hold the lock.
14pub const Lock = struct {12pub const Lock = struct {
...@@ -17,7 +15,7 @@ pub const Lock = struct {...@@ -17,7 +15,7 @@ pub const Lock = struct {
17 queue: Queue,15 queue: Queue,
18 queue_empty_bit: u8, // TODO make this a bool16 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
22 pub const Held = struct {20 pub const Held = struct {
23 lock: *Lock,21 lock: *Lock,
...@@ -30,19 +28,19 @@ pub const Lock = struct {...@@ -30,19 +28,19 @@ pub const Lock = struct {
30 }28 }
3129
32 // We need to release the lock.30 // We need to release the lock.
33 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);31 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
34 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);32 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
3533
36 // There might be a queue item. If we know the queue is empty, we can be done,34 // There might be a queue item. If we know the queue is empty, we can be done,
37 // because the other actor will try to obtain the lock.35 // because the other actor will try to obtain the lock.
38 // But if there's a queue item, we are the actor which must loop and attempt36 // But if there's a queue item, we are the actor which must loop and attempt
39 // to grab the lock again.37 // 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) {
41 return;39 return;
42 }40 }
4341
44 while (true) {42 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);
46 if (old_bit != 0) {44 if (old_bit != 0) {
47 // We did not obtain the lock. Great, the queue is someone else's problem.45 // We did not obtain the lock. Great, the queue is someone else's problem.
48 return;46 return;
...@@ -55,11 +53,11 @@ pub const Lock = struct {...@@ -55,11 +53,11 @@ pub const Lock = struct {
55 }53 }
5654
57 // Release the lock again.55 // Release the lock again.
58 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);56 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
59 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);57 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
6058
61 // Find out if we can be done.59 // 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) {
63 return;61 return;
64 }62 }
65 }63 }
...@@ -88,28 +86,23 @@ pub const Lock = struct {...@@ -88,28 +86,23 @@ pub const Lock = struct {
88 /// All calls to acquire() and release() must complete before calling deinit().86 /// All calls to acquire() and release() must complete before calling deinit().
89 pub fn deinit(self: *Lock) void {87 pub fn deinit(self: *Lock) void {
90 assert(self.shared_bit == 0);88 assert(self.shared_bit == 0);
91 while (self.queue.get()) |node| cancel node.data;89 while (self.queue.get()) |node| resume node.data;
92 }90 }
9391
94 pub async fn acquire(self: *Lock) Held {92 pub async fn acquire(self: *Lock) Held {
95 // TODO explicitly put this memory in the coroutine frame #119493 var my_tick_node = Loop.NextTickNode.init(@frame());
96 suspend {
97 resume @handle();
98 }
99 var my_tick_node = Loop.NextTickNode.init(@handle());
10094
101 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire95 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
102 suspend {96 suspend {
103 self.queue.put(&my_tick_node);97 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 coroutine99 // At this point, we are in the queue, so we might have already been resumed.
106 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
107100
108 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor101 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
109 // will attempt to grab the lock.102 // 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);
113 if (old_bit == 0) {106 if (old_bit == 0) {
114 if (self.queue.get()) |node| {107 if (self.queue.get()) |node| {
115 // Whether this node is us or someone else, we tail resume it.108 // Whether this node is us or someone else, we tail resume it.
...@@ -123,8 +116,7 @@ pub const Lock = struct {...@@ -123,8 +116,7 @@ pub const Lock = struct {
123};116};
124117
125test "std.event.Lock" {118test "std.event.Lock" {
126 // TODO https://github.com/ziglang/zig/issues/2377119 // TODO https://github.com/ziglang/zig/issues/1908
127 if (true) return error.SkipZigTest;
128 if (builtin.single_threaded) return error.SkipZigTest;120 if (builtin.single_threaded) return error.SkipZigTest;
129121
130 const allocator = std.heap.direct_allocator;122 const allocator = std.heap.direct_allocator;
...@@ -136,39 +128,34 @@ test "std.event.Lock" {...@@ -136,39 +128,34 @@ test "std.event.Lock" {
136 var lock = Lock.init(&loop);128 var lock = Lock.init(&loop);
137 defer lock.deinit();129 defer lock.deinit();
138130
139 const handle = try async<allocator> testLock(&loop, &lock);131 _ = async testLock(&loop, &lock);
140 defer cancel handle;
141 loop.run();132 loop.run();
142133
143 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);134 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
144}135}
145136
146async fn testLock(loop: *Loop, lock: *Lock) void {137async fn testLock(loop: *Loop, lock: *Lock) void {
147 // TODO explicitly put next tick node memory in the coroutine frame #1194138 const handle1 = async lockRunner(lock);
148 suspend {
149 resume @handle();
150 }
151 const handle1 = async lockRunner(lock) catch @panic("out of memory");
152 var tick_node1 = Loop.NextTickNode{139 var tick_node1 = Loop.NextTickNode{
153 .prev = undefined,140 .prev = undefined,
154 .next = undefined,141 .next = undefined,
155 .data = handle1,142 .data = &handle1,
156 };143 };
157 loop.onNextTick(&tick_node1);144 loop.onNextTick(&tick_node1);
158145
159 const handle2 = async lockRunner(lock) catch @panic("out of memory");146 const handle2 = async lockRunner(lock);
160 var tick_node2 = Loop.NextTickNode{147 var tick_node2 = Loop.NextTickNode{
161 .prev = undefined,148 .prev = undefined,
162 .next = undefined,149 .next = undefined,
163 .data = handle2,150 .data = &handle2,
164 };151 };
165 loop.onNextTick(&tick_node2);152 loop.onNextTick(&tick_node2);
166153
167 const handle3 = async lockRunner(lock) catch @panic("out of memory");154 const handle3 = async lockRunner(lock);
168 var tick_node3 = Loop.NextTickNode{155 var tick_node3 = Loop.NextTickNode{
169 .prev = undefined,156 .prev = undefined,
170 .next = undefined,157 .next = undefined,
171 .data = handle3,158 .data = &handle3,
172 };159 };
173 loop.onNextTick(&tick_node3);160 loop.onNextTick(&tick_node3);
174161
...@@ -185,7 +172,7 @@ async fn lockRunner(lock: *Lock) void {...@@ -185,7 +172,7 @@ async fn lockRunner(lock: *Lock) void {
185172
186 var i: usize = 0;173 var i: usize = 0;
187 while (i < shared_test_data.len) : (i += 1) {174 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();
189 const handle = await lock_promise;176 const handle = await lock_promise;
190 defer handle.release();177 defer handle.release();
191178
std/event/locked.zig+1-1
...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await lock that protects one piece of data.5/// Thread-safe async/await lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and6/// Functions which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn Locked(comptime T: type) type {8pub fn Locked(comptime T: type) type {
9 return struct {9 return struct {
std/event/loop.zig+83-69
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const root = @import("root");
3const assert = std.debug.assert;4const assert = std.debug.assert;
4const testing = std.testing;5const testing = std.testing;
5const mem = std.mem;6const mem = std.mem;
...@@ -13,7 +14,7 @@ const Thread = std.Thread;...@@ -13,7 +14,7 @@ const Thread = std.Thread;
1314
14pub const Loop = struct {15pub const Loop = struct {
15 allocator: *mem.Allocator,16 allocator: *mem.Allocator,
16 next_tick_queue: std.atomic.Queue(promise),17 next_tick_queue: std.atomic.Queue(anyframe),
17 os_data: OsData,18 os_data: OsData,
18 final_resume_node: ResumeNode,19 final_resume_node: ResumeNode,
19 pending_event_count: usize,20 pending_event_count: usize,
...@@ -24,11 +25,11 @@ pub const Loop = struct {...@@ -24,11 +25,11 @@ pub const Loop = struct {
24 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),25 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
25 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,26 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
29 pub const ResumeNode = struct {30 pub const ResumeNode = struct {
30 id: Id,31 id: Id,
31 handle: promise,32 handle: anyframe,
32 overlapped: Overlapped,33 overlapped: Overlapped,
3334
34 pub const overlapped_init = switch (builtin.os) {35 pub const overlapped_init = switch (builtin.os) {
...@@ -85,18 +86,43 @@ pub const Loop = struct {...@@ -85,18 +86,43 @@ pub const Loop = struct {
85 };86 };
86 };87 };
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
88 /// After initialization, call run().112 /// After initialization, call run().
89 /// TODO copy elision / named return values so that the threads referencing *Loop113 /// TODO copy elision / named return values so that the threads referencing *Loop
90 /// have the correct pointer value.114 /// have the correct pointer value.
115 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
91 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {116 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {
92 return self.initInternal(allocator, 1);117 return self.initInternal(allocator, 1);
93 }118 }
94119
95 /// The allocator must be thread-safe because we use it for multiplexing120 /// The allocator must be thread-safe because we use it for multiplexing
96 /// coroutines onto kernel threads.121 /// async functions onto kernel threads.
97 /// After initialization, call run().122 /// After initialization, call run().
98 /// TODO copy elision / named return values so that the threads referencing *Loop123 /// TODO copy elision / named return values so that the threads referencing *Loop
99 /// have the correct pointer value.124 /// have the correct pointer value.
125 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
100 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {126 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
101 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");127 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
102 const core_count = try Thread.cpuCount();128 const core_count = try Thread.cpuCount();
...@@ -110,7 +136,7 @@ pub const Loop = struct {...@@ -110,7 +136,7 @@ pub const Loop = struct {
110 .pending_event_count = 1,136 .pending_event_count = 1,
111 .allocator = allocator,137 .allocator = allocator,
112 .os_data = undefined,138 .os_data = undefined,
113 .next_tick_queue = std.atomic.Queue(promise).init(),139 .next_tick_queue = std.atomic.Queue(anyframe).init(),
114 .extra_threads = undefined,140 .extra_threads = undefined,
115 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),141 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
116 .eventfd_resume_nodes = undefined,142 .eventfd_resume_nodes = undefined,
...@@ -397,7 +423,7 @@ pub const Loop = struct {...@@ -397,7 +423,7 @@ pub const Loop = struct {
397 }423 }
398 }424 }
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.
401 /// flags must contain EPOLLET427 /// flags must contain EPOLLET
402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {428 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403 assert(flags & os.EPOLLET == os.EPOLLET);429 assert(flags & os.EPOLLET == os.EPOLLET);
...@@ -428,11 +454,10 @@ pub const Loop = struct {...@@ -428,11 +454,10 @@ pub const Loop = struct {
428 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {454 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {
429 defer self.linuxRemoveFd(fd);455 defer self.linuxRemoveFd(fd);
430 suspend {456 suspend {
431 // TODO explicitly put this memory in the coroutine frame #1194
432 var resume_node = ResumeNode.Basic{457 var resume_node = ResumeNode.Basic{
433 .base = ResumeNode{458 .base = ResumeNode{
434 .id = ResumeNode.Id.Basic,459 .id = ResumeNode.Id.Basic,
435 .handle = @handle(),460 .handle = @frame(),
436 .overlapped = ResumeNode.overlapped_init,461 .overlapped = ResumeNode.overlapped_init,
437 },462 },
438 };463 };
...@@ -441,14 +466,10 @@ pub const Loop = struct {...@@ -441,14 +466,10 @@ pub const Loop = struct {
441 }466 }
442467
443 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {468 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
444 // TODO #1194
445 suspend {
446 resume @handle();
447 }
448 var resume_node = ResumeNode.Basic{469 var resume_node = ResumeNode.Basic{
449 .base = ResumeNode{470 .base = ResumeNode{
450 .id = ResumeNode.Id.Basic,471 .id = ResumeNode.Id.Basic,
451 .handle = @handle(),472 .handle = @frame(),
452 .overlapped = ResumeNode.overlapped_init,473 .overlapped = ResumeNode.overlapped_init,
453 },474 },
454 .kev = undefined,475 .kev = undefined,
...@@ -460,7 +481,7 @@ pub const Loop = struct {...@@ -460,7 +481,7 @@ pub const Loop = struct {
460 return resume_node.kev;481 return resume_node.kev;
461 }482 }
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.
464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {485 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465 self.beginOneEvent();486 self.beginOneEvent();
466 errdefer self.finishOneEvent();487 errdefer self.finishOneEvent();
...@@ -561,10 +582,10 @@ pub const Loop = struct {...@@ -561,10 +582,10 @@ pub const Loop = struct {
561 self.workerRun();582 self.workerRun();
562583
563 switch (builtin.os) {584 switch (builtin.os) {
564 builtin.Os.linux,585 .linux,
565 builtin.Os.macosx,586 .macosx,
566 builtin.Os.freebsd,587 .freebsd,
567 builtin.Os.netbsd,588 .netbsd,
568 => self.os_data.fs_thread.wait(),589 => self.os_data.fs_thread.wait(),
569 else => {},590 else => {},
570 }591 }
...@@ -574,45 +595,39 @@ pub const Loop = struct {...@@ -574,45 +595,39 @@ pub const Loop = struct {
574 }595 }
575 }596 }
576597
577 /// This is equivalent to an async call, except instead of beginning execution of the async function,598 /// This is equivalent to function call, except it calls `startCpuBoundOperation` first.
578 /// it immediately returns to the caller, and the async function is queued in the event loop. It still599 pub fn call(comptime func: var, args: ...) @typeOf(func).ReturnType {
579 /// returns a promise to be awaited.600 startCpuBoundOperation();
580 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {601 return func(args);
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 }602 }
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.
601 /// Note that async operations automatically start when a function yields for any other reason,605 /// Note that async operations automatically start when a function yields for any other reason,
602 /// for example, when async I/O is performed. This function is intended to be used only when606 /// for example, when async I/O is performed. This function is intended to be used only when
603 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O607 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
604 /// is performed.608 /// is performed.
605 pub async fn yield(self: *Loop) void {609 pub fn yield(self: *Loop) void {
606 suspend {610 suspend {
607 var my_tick_node = Loop.NextTickNode{611 var my_tick_node = NextTickNode{
608 .prev = undefined,612 .prev = undefined,
609 .next = undefined,613 .next = undefined,
610 .data = @handle(),614 .data = @frame(),
611 };615 };
612 self.onNextTick(&my_tick_node);616 self.onNextTick(&my_tick_node);
613 }617 }
614 }618 }
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
616 /// call finishOneEvent when done631 /// call finishOneEvent when done
617 pub fn beginOneEvent(self: *Loop) void {632 pub fn beginOneEvent(self: *Loop) void {
618 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);633 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
...@@ -672,9 +687,9 @@ pub const Loop = struct {...@@ -672,9 +687,9 @@ pub const Loop = struct {
672 const handle = resume_node.handle;687 const handle = resume_node.handle;
673 const resume_node_id = resume_node.id;688 const resume_node_id = resume_node.id;
674 switch (resume_node_id) {689 switch (resume_node_id) {
675 ResumeNode.Id.Basic => {},690 .Basic => {},
676 ResumeNode.Id.Stop => return,691 .Stop => return,
677 ResumeNode.Id.EventFd => {692 .EventFd => {
678 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);693 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;694 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);695 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
...@@ -696,12 +711,12 @@ pub const Loop = struct {...@@ -696,12 +711,12 @@ pub const Loop = struct {
696 const handle = resume_node.handle;711 const handle = resume_node.handle;
697 const resume_node_id = resume_node.id;712 const resume_node_id = resume_node.id;
698 switch (resume_node_id) {713 switch (resume_node_id) {
699 ResumeNode.Id.Basic => {714 .Basic => {
700 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);715 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);
701 basic_node.kev = ev;716 basic_node.kev = ev;
702 },717 },
703 ResumeNode.Id.Stop => return,718 .Stop => return,
704 ResumeNode.Id.EventFd => {719 .EventFd => {
705 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);720 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
706 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);721 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
707 self.available_eventfd_resume_nodes.push(stack_node);722 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -730,9 +745,9 @@ pub const Loop = struct {...@@ -730,9 +745,9 @@ pub const Loop = struct {
730 const handle = resume_node.handle;745 const handle = resume_node.handle;
731 const resume_node_id = resume_node.id;746 const resume_node_id = resume_node.id;
732 switch (resume_node_id) {747 switch (resume_node_id) {
733 ResumeNode.Id.Basic => {},748 .Basic => {},
734 ResumeNode.Id.Stop => return,749 .Stop => return,
735 ResumeNode.Id.EventFd => {750 .EventFd => {
736 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);751 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
737 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);752 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
738 self.available_eventfd_resume_nodes.push(stack_node);753 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -750,12 +765,12 @@ pub const Loop = struct {...@@ -750,12 +765,12 @@ pub const Loop = struct {
750 self.beginOneEvent(); // finished in posixFsRun after processing the msg765 self.beginOneEvent(); // finished in posixFsRun after processing the msg
751 self.os_data.fs_queue.put(request_node);766 self.os_data.fs_queue.put(request_node);
752 switch (builtin.os) {767 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {768 .macosx, .freebsd, .netbsd => {
754 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);769 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];770 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;771 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757 },772 },
758 builtin.Os.linux => {773 .linux => {
759 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);774 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);775 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761 switch (os.linux.getErrno(rc)) {776 switch (os.linux.getErrno(rc)) {
...@@ -781,18 +796,18 @@ pub const Loop = struct {...@@ -781,18 +796,18 @@ pub const Loop = struct {
781 }796 }
782 while (self.os_data.fs_queue.get()) |node| {797 while (self.os_data.fs_queue.get()) |node| {
783 switch (node.data.msg) {798 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,799 .End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {800 .PWriteV => |*msg| {
786 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);801 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787 },802 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {803 .PReadV => |*msg| {
789 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);804 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790 },805 },
791 @TagType(fs.Request.Msg).Open => |*msg| {806 .Open => |*msg| {
792 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);807 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793 },808 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),809 .Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {810 .WriteFile => |*msg| blk: {
796 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |811 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797 os.O_CLOEXEC | os.O_TRUNC;812 os.O_CLOEXEC | os.O_TRUNC;
798 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {813 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
...@@ -804,11 +819,11 @@ pub const Loop = struct {...@@ -804,11 +819,11 @@ pub const Loop = struct {
804 },819 },
805 }820 }
806 switch (node.data.finish) {821 switch (node.data.finish) {
807 @TagType(fs.Request.Finish).TickNode => |*tick_node| self.onNextTick(tick_node),822 .TickNode => |*tick_node| self.onNextTick(tick_node),
808 @TagType(fs.Request.Finish).DeallocCloseOperation => |close_op| {823 .DeallocCloseOperation => |close_op| {
809 self.allocator.destroy(close_op);824 self.allocator.destroy(close_op);
810 },825 },
811 @TagType(fs.Request.Finish).NoAction => {},826 .NoAction => {},
812 }827 }
813 self.finishOneEvent();828 self.finishOneEvent();
814 }829 }
...@@ -864,7 +879,7 @@ pub const Loop = struct {...@@ -864,7 +879,7 @@ pub const Loop = struct {
864879
865test "std.event.Loop - basic" {880test "std.event.Loop - basic" {
866 // https://github.com/ziglang/zig/issues/1908881 // 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
869 const allocator = std.heap.direct_allocator;884 const allocator = std.heap.direct_allocator;
870885
...@@ -877,7 +892,7 @@ test "std.event.Loop - basic" {...@@ -877,7 +892,7 @@ test "std.event.Loop - basic" {
877892
878test "std.event.Loop - call" {893test "std.event.Loop - call" {
879 // https://github.com/ziglang/zig/issues/1908894 // 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
882 const allocator = std.heap.direct_allocator;897 const allocator = std.heap.direct_allocator;
883898
...@@ -886,9 +901,8 @@ test "std.event.Loop - call" {...@@ -886,9 +901,8 @@ test "std.event.Loop - call" {
886 defer loop.deinit();901 defer loop.deinit();
887902
888 var did_it = false;903 var did_it = false;
889 const handle = try loop.call(testEventLoop);904 const handle = async Loop.call(testEventLoop);
890 const handle2 = try loop.call(testEventLoop2, handle, &did_it);905 const handle2 = async Loop.call(testEventLoop2, &handle, &did_it);
891 defer cancel handle2;
892906
893 loop.run();907 loop.run();
894908
...@@ -899,7 +913,7 @@ async fn testEventLoop() i32 {...@@ -899,7 +913,7 @@ async fn testEventLoop() i32 {
899 return 1234;913 return 1234;
900}914}
901915
902async fn testEventLoop2(h: promise->i32, did_it: *bool) void {916async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
903 const value = await h;917 const value = await h;
904 testing.expect(value == 1234);918 testing.expect(value == 1234);
905 did_it.* = true;919 did_it.* = true;
std/event/net.zig+27-38
...@@ -9,24 +9,24 @@ const File = std.fs.File;...@@ -9,24 +9,24 @@ const File = std.fs.File;
9const fd_t = os.fd_t;9const fd_t = os.fd_t;
1010
11pub const Server = struct {11pub 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
14 loop: *Loop,14 loop: *Loop,
15 sockfd: ?i32,15 sockfd: ?i32,
16 accept_coro: ?promise,16 accept_frame: ?anyframe,
17 listen_address: std.net.Address,17 listen_address: std.net.Address,
1818
19 waiting_for_emfile_node: PromiseNode,19 waiting_for_emfile_node: PromiseNode,
20 listen_resume_node: event.Loop.ResumeNode,20 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.TailQueue(promise).Node;22 const PromiseNode = std.TailQueue(anyframe).Node;
2323
24 pub fn init(loop: *Loop) Server {24 pub fn init(loop: *Loop) Server {
25 // TODO can't initialize handler coroutine here because we need well defined copy elision25 // TODO can't initialize handler here because we need well defined copy elision
26 return Server{26 return Server{
27 .loop = loop,27 .loop = loop,
28 .sockfd = null,28 .sockfd = null,
29 .accept_coro = null,29 .accept_frame = null,
30 .handleRequestFn = undefined,30 .handleRequestFn = undefined,
31 .waiting_for_emfile_node = undefined,31 .waiting_for_emfile_node = undefined,
32 .listen_address = undefined,32 .listen_address = undefined,
...@@ -41,7 +41,7 @@ pub const Server = struct {...@@ -41,7 +41,7 @@ pub const Server = struct {
41 pub fn listen(41 pub fn listen(
42 self: *Server,42 self: *Server,
43 address: *const std.net.Address,43 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,
45 ) !void {45 ) !void {
46 self.handleRequestFn = handleRequestFn;46 self.handleRequestFn = handleRequestFn;
4747
...@@ -53,10 +53,10 @@ pub const Server = struct {...@@ -53,10 +53,10 @@ pub const Server = struct {
53 try os.listen(sockfd, os.SOMAXCONN);53 try os.listen(sockfd, os.SOMAXCONN);
54 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));54 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
5555
56 self.accept_coro = try async<self.loop.allocator> Server.handler(self);56 self.accept_frame = async Server.handler(self);
57 errdefer cancel self.accept_coro.?;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.?;
60 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);60 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
61 errdefer self.loop.removeFd(sockfd);61 errdefer self.loop.removeFd(sockfd);
62 }62 }
...@@ -71,7 +71,7 @@ pub const Server = struct {...@@ -71,7 +71,7 @@ pub const Server = struct {
71 }71 }
7272
73 pub fn deinit(self: *Server) void {73 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;
75 if (self.sockfd) |sockfd| os.close(sockfd);75 if (self.sockfd) |sockfd| os.close(sockfd);
76 }76 }
7777
...@@ -86,12 +86,7 @@ pub const Server = struct {...@@ -86,12 +86,7 @@ pub const Server = struct {
86 continue;86 continue;
87 }87 }
88 var socket = File.openHandle(accepted_fd);88 var socket = File.openHandle(accepted_fd);
89 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {89 self.handleRequestFn(self, &accepted_addr, socket);
90 error.OutOfMemory => {
91 socket.close();
92 continue;
93 },
94 };
95 } else |err| switch (err) {90 } else |err| switch (err) {
96 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),91 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
97 error.ConnectionAborted => continue,92 error.ConnectionAborted => continue,
...@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {...@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
124 mem.copy(u8, sock_addr.path[0..], path);119 mem.copy(u8, sock_addr.path[0..], path);
125 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);120 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
126 try os.connect_async(sockfd, &sock_addr, size);121 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);
128 try os.getsockoptError(sockfd);123 try os.getsockoptError(sockfd);
129124
130 return sockfd;125 return sockfd;
...@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize...@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize
149 .iov_len = buffer.len,144 .iov_len = buffer.len,
150 };145 };
151 const iovs: *const [1]os.iovec = &iov;146 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);
153}148}
154149
155pub const WriteError = error{};150pub const WriteError = error{};
...@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr...@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr
160 .iov_len = buffer.len,155 .iov_len = buffer.len,
161 };156 };
162 const iovs: *const [1]os.iovec_const = &iov;157 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);
164}159}
165160
166pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {161pub 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...@@ -174,7 +169,7 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, cou
174 os.EINVAL => unreachable,169 os.EINVAL => unreachable,
175 os.EFAULT => unreachable,170 os.EFAULT => unreachable,
176 os.EAGAIN => {171 os.EAGAIN => {
177 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);172 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT);
178 continue;173 continue;
179 },174 },
180 os.EBADF => unreachable, // always a race condition175 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:...@@ -205,7 +200,7 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count:
205 os.EINVAL => unreachable,200 os.EINVAL => unreachable,
206 os.EFAULT => unreachable,201 os.EFAULT => unreachable,
207 os.EAGAIN => {202 os.EAGAIN => {
208 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);203 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
209 continue;204 continue;
210 },205 },
211 os.EBADF => unreachable, // always a race condition206 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 {...@@ -232,7 +227,7 @@ pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
232 };227 };
233 }228 }
234229
235 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);230 return writevPosix(loop, fd, iovecs.ptr, data.len);
236}231}
237232
238pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {233pub 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 {...@@ -246,7 +241,7 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
246 };241 };
247 }242 }
248243
249 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);244 return readvPosix(loop, fd, iovecs.ptr, data.len);
250}245}
251246
252pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {247pub 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 {...@@ -256,7 +251,7 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
256 errdefer os.close(sockfd);251 errdefer os.close(sockfd);
257252
258 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));253 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);
260 try os.getsockoptError(sockfd);255 try os.getsockoptError(sockfd);
261256
262 return File.openHandle(sockfd);257 return File.openHandle(sockfd);
...@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {...@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {
275 tcp_server: Server,270 tcp_server: Server,
276271
277 const Self = @This();272 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 {
279 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);274 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
280 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592275 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
281 defer socket.close();276 defer socket.close();
282 // TODO guarantee elision of this allocation277 const next_handler = errorableHandler(self, _addr, socket) catch |err| {
283 const next_handler = async errorableHandler(self, _addr, socket) catch unreachable;
284 (await next_handler) catch |err| {
285 std.debug.panic("unable to handle connection: {}\n", err);278 std.debug.panic("unable to handle connection: {}\n", err);
286 };279 };
287 suspend {
288 cancel @handle();
289 }
290 }280 }
291 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {281 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
292 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592282 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
...@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {...@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {
306 defer server.tcp_server.deinit();296 defer server.tcp_server.deinit();
307 try server.tcp_server.listen(&addr, MyServer.handler);297 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);299 _ = async doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
310 defer cancel p;
311 loop.run();300 loop.run();
312}301}
313302
314async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {303async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
315 errdefer @panic("test failure");304 errdefer @panic("test failure");
316305
317 var socket_file = try await try async connect(loop, address);306 var socket_file = try connect(loop, address);
318 defer socket_file.close();307 defer socket_file.close();
319308
320 var buf: [512]u8 = undefined;309 var buf: [512]u8 = undefined;
...@@ -340,9 +329,9 @@ pub const OutStream = struct {...@@ -340,9 +329,9 @@ pub const OutStream = struct {
340 };329 };
341 }330 }
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 {
344 const self = @fieldParentPtr(OutStream, "stream", out_stream);333 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);
346 }335 }
347};336};
348337
...@@ -362,8 +351,8 @@ pub const InStream = struct {...@@ -362,8 +351,8 @@ pub const InStream = struct {
362 };351 };
363 }352 }
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 {
366 const self = @fieldParentPtr(InStream, "stream", in_stream);355 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);
368 }357 }
369};358};
std/event/rwlock.zig+46-47
...@@ -3,12 +3,10 @@ const builtin = @import("builtin");...@@ -3,12 +3,10 @@ const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// Thread-safe async/await lock.8/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and9/// Functions which are waiting for the lock are suspended, and
12/// are resumed when the lock is released, in order.10/// are resumed when the lock is released, in order.
13/// Many readers can hold the lock at the same time; however locking for writing is exclusive.11/// Many readers can hold the lock at the same time; however locking for writing is exclusive.
14/// When a read lock is held, it will not be released until the reader queue is empty.12/// 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 {...@@ -28,19 +26,19 @@ pub const RwLock = struct {
28 const ReadLock = 2;26 const ReadLock = 2;
29 };27 };
3028
31 const Queue = std.atomic.Queue(promise);29 const Queue = std.atomic.Queue(anyframe);
3230
33 pub const HeldRead = struct {31 pub const HeldRead = struct {
34 lock: *RwLock,32 lock: *RwLock,
3533
36 pub fn release(self: HeldRead) void {34 pub fn release(self: HeldRead) void {
37 // If other readers still hold the lock, we're done.35 // 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) {
39 return;37 return;
40 }38 }
4139
42 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);40 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
43 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {41 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
44 // Didn't unlock. Someone else's problem.42 // Didn't unlock. Someone else's problem.
45 return;43 return;
46 }44 }
...@@ -61,17 +59,17 @@ pub const RwLock = struct {...@@ -61,17 +59,17 @@ pub const RwLock = struct {
61 }59 }
6260
63 // We need to release the write lock. Check if any readers are waiting to grab the lock.61 // 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) {
65 // Switch to a read lock.63 // 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);
67 while (self.lock.reader_queue.get()) |node| {65 while (self.lock.reader_queue.get()) |node| {
68 self.lock.loop.onNextTick(node);66 self.lock.loop.onNextTick(node);
69 }67 }
70 return;68 return;
71 }69 }
7270
73 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);71 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
74 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);72 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.Unlocked, .SeqCst);
7573
76 self.lock.commonPostUnlock();74 self.lock.commonPostUnlock();
77 }75 }
...@@ -93,32 +91,30 @@ pub const RwLock = struct {...@@ -93,32 +91,30 @@ pub const RwLock = struct {
93 /// All calls to acquire() and release() must complete before calling deinit().91 /// All calls to acquire() and release() must complete before calling deinit().
94 pub fn deinit(self: *RwLock) void {92 pub fn deinit(self: *RwLock) void {
95 assert(self.shared_state == State.Unlocked);93 assert(self.shared_state == State.Unlocked);
96 while (self.writer_queue.get()) |node| cancel node.data;94 while (self.writer_queue.get()) |node| resume node.data;
97 while (self.reader_queue.get()) |node| cancel node.data;95 while (self.reader_queue.get()) |node| resume node.data;
98 }96 }
9997
100 pub async fn acquireRead(self: *RwLock) HeldRead {98 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
103 suspend {101 suspend {
104 // TODO explicitly put this memory in the coroutine frame #1194
105 var my_tick_node = Loop.NextTickNode{102 var my_tick_node = Loop.NextTickNode{
106 .data = @handle(),103 .data = @frame(),
107 .prev = undefined,104 .prev = undefined,
108 .next = undefined,105 .next = undefined,
109 };106 };
110107
111 self.reader_queue.put(&my_tick_node);108 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 coroutine110 // At this point, we are in the reader_queue, so we might have already been resumed.
114 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
115111
116 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,112 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
117 // some actor will attempt to grab the lock.113 // 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
120 // Here we don't care if we are the one to do the locking or if it was already locked for reading.116 // 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;
122 if (have_read_lock) {118 if (have_read_lock) {
123 // Give out all the read locks.119 // Give out all the read locks.
124 if (self.reader_queue.get()) |first_node| {120 if (self.reader_queue.get()) |first_node| {
...@@ -134,24 +130,22 @@ pub const RwLock = struct {...@@ -134,24 +130,22 @@ pub const RwLock = struct {
134130
135 pub async fn acquireWrite(self: *RwLock) HeldWrite {131 pub async fn acquireWrite(self: *RwLock) HeldWrite {
136 suspend {132 suspend {
137 // TODO explicitly put this memory in the coroutine frame #1194
138 var my_tick_node = Loop.NextTickNode{133 var my_tick_node = Loop.NextTickNode{
139 .data = @handle(),134 .data = @frame(),
140 .prev = undefined,135 .prev = undefined,
141 .next = undefined,136 .next = undefined,
142 };137 };
143138
144 self.writer_queue.put(&my_tick_node);139 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 coroutine141 // At this point, we are in the writer_queue, so we might have already been resumed.
147 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
148142
149 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,143 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
150 // some actor will attempt to grab the lock.144 // 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
153 // Here we must be the one to acquire the write lock. It cannot already be locked.147 // 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) {
155 // We now have a write lock.149 // We now have a write lock.
156 if (self.writer_queue.get()) |node| {150 if (self.writer_queue.get()) |node| {
157 // Whether this node is us or someone else, we tail resume it.151 // Whether this node is us or someone else, we tail resume it.
...@@ -169,8 +163,8 @@ pub const RwLock = struct {...@@ -169,8 +163,8 @@ pub const RwLock = struct {
169 // obtain the lock.163 // obtain the lock.
170 // But if there's a writer_queue item or a reader_queue item,164 // But if there's a writer_queue item or a reader_queue item,
171 // we are the actor which must loop and attempt to grab the lock again.165 // 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) {166 if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
173 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {167 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) != null) {
174 // We did not obtain the lock. Great, the queues are someone else's problem.168 // We did not obtain the lock. Great, the queues are someone else's problem.
175 return;169 return;
176 }170 }
...@@ -180,13 +174,13 @@ pub const RwLock = struct {...@@ -180,13 +174,13 @@ pub const RwLock = struct {
180 return;174 return;
181 }175 }
182 // Release the lock again.176 // Release the lock again.
183 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);177 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
184 _ = @atomicRmw(u8, &self.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);178 _ = @atomicRmw(u8, &self.shared_state, .Xchg, State.Unlocked, .SeqCst);
185 continue;179 continue;
186 }180 }
187181
188 if (@atomicLoad(u8, &self.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {182 if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
189 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {183 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst) != null) {
190 // We did not obtain the lock. Great, the queues are someone else's problem.184 // We did not obtain the lock. Great, the queues are someone else's problem.
191 return;185 return;
192 }186 }
...@@ -199,8 +193,8 @@ pub const RwLock = struct {...@@ -199,8 +193,8 @@ pub const RwLock = struct {
199 return;193 return;
200 }194 }
201 // Release the lock again.195 // Release the lock again.
202 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);196 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
203 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {197 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
204 // Didn't unlock. Someone else's problem.198 // Didn't unlock. Someone else's problem.
205 return;199 return;
206 }200 }
...@@ -215,6 +209,9 @@ test "std.event.RwLock" {...@@ -215,6 +209,9 @@ test "std.event.RwLock" {
215 // https://github.com/ziglang/zig/issues/2377209 // https://github.com/ziglang/zig/issues/2377
216 if (true) return error.SkipZigTest;210 if (true) return error.SkipZigTest;
217211
212 // https://github.com/ziglang/zig/issues/1908
213 if (builtin.single_threaded) return error.SkipZigTest;
214
218 const allocator = std.heap.direct_allocator;215 const allocator = std.heap.direct_allocator;
219216
220 var loop: Loop = undefined;217 var loop: Loop = undefined;
...@@ -224,8 +221,7 @@ test "std.event.RwLock" {...@@ -224,8 +221,7 @@ test "std.event.RwLock" {
224 var lock = RwLock.init(&loop);221 var lock = RwLock.init(&loop);
225 defer lock.deinit();222 defer lock.deinit();
226223
227 const handle = try async<allocator> testLock(&loop, &lock);224 const handle = testLock(&loop, &lock);
228 defer cancel handle;
229 loop.run();225 loop.run();
230226
231 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;227 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" {...@@ -233,28 +229,31 @@ test "std.event.RwLock" {
233}229}
234230
235async fn testLock(loop: *Loop, lock: *RwLock) void {231async 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
241 var read_nodes: [100]Loop.NextTickNode = undefined;232 var read_nodes: [100]Loop.NextTickNode = undefined;
242 for (read_nodes) |*read_node| {233 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);
244 loop.onNextTick(read_node);237 loop.onNextTick(read_node);
245 }238 }
246239
247 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;240 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;
248 for (write_nodes) |*write_node| {241 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);
250 loop.onNextTick(write_node);245 loop.onNextTick(write_node);
251 }246 }
252247
253 for (write_nodes) |*write_node| {248 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);
255 }252 }
256 for (read_nodes) |*read_node| {253 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);
258 }257 }
259}258}
260259
...@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {...@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {
269 var i: usize = 0;268 var i: usize = 0;
270 while (i < shared_test_data.len) : (i += 1) {269 while (i < shared_test_data.len) : (i += 1) {
271 std.time.sleep(100 * std.time.microsecond);270 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();
273 const handle = await lock_promise;272 const handle = await lock_promise;
274 defer handle.release();273 defer handle.release();
275274
...@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {...@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {
287286
288 var i: usize = 0;287 var i: usize = 0;
289 while (i < shared_test_data.len) : (i += 1) {288 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();
291 const handle = await lock_promise;290 const handle = await lock_promise;
292 defer handle.release();291 defer handle.release();
293292
std/event/rwlocked.zig+1-1
...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await RW lock that protects one piece of data.5/// Thread-safe async/await RW lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and6/// Functions which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn RwLocked(comptime T: type) type {8pub fn RwLocked(comptime T: type) type {
9 return struct {9 return struct {
std/fmt.zig-3
...@@ -328,9 +328,6 @@ pub fn formatType(...@@ -328,9 +328,6 @@ pub fn formatType(
328 try output(context, "error.");328 try output(context, "error.");
329 return output(context, @errorName(value));329 return output(context, @errorName(value));
330 },330 },
331 .Promise => {
332 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
333 },
334 .Enum => {331 .Enum => {
335 if (comptime std.meta.trait.hasFn("format")(T)) {332 if (comptime std.meta.trait.hasFn("format")(T)) {
336 return value.format(fmt, options, context, Errors, output);333 return value.format(fmt, options, context, Errors, output);
std/hash/auto_hash.zig+25-24
...@@ -8,31 +8,32 @@ const meta = std.meta;...@@ -8,31 +8,32 @@ const meta = std.meta;
8pub fn autoHash(hasher: var, key: var) void {8pub fn autoHash(hasher: var, key: var) void {
9 const Key = @typeOf(key);9 const Key = @typeOf(key);
10 switch (@typeInfo(Key)) {10 switch (@typeInfo(Key)) {
11 builtin.TypeId.NoReturn,11 .NoReturn,
12 builtin.TypeId.Opaque,12 .Opaque,
13 builtin.TypeId.Undefined,13 .Undefined,
14 builtin.TypeId.ArgTuple,14 .ArgTuple,
15 builtin.TypeId.Void,15 .Void,
16 builtin.TypeId.Null,16 .Null,
17 builtin.TypeId.BoundFn,17 .BoundFn,
18 builtin.TypeId.ComptimeFloat,18 .ComptimeFloat,
19 builtin.TypeId.ComptimeInt,19 .ComptimeInt,
20 builtin.TypeId.Type,20 .Type,
21 builtin.TypeId.EnumLiteral,21 .EnumLiteral,
22 .Frame,
22 => @compileError("cannot hash this type"),23 => @compileError("cannot hash this type"),
2324
24 // Help the optimizer see that hashing an int is easy by inlining!25 // Help the optimizer see that hashing an int is easy by inlining!
25 // TODO Check if the situation is better after #561 is resolved.26 // 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 .Bool => autoHash(hasher, @boolToInt(key)),
31 builtin.TypeId.Enum => autoHash(hasher, @enumToInt(key)),32 .Enum => autoHash(hasher, @enumToInt(key)),
32 builtin.TypeId.ErrorSet => autoHash(hasher, @errorToInt(key)),33 .ErrorSet => autoHash(hasher, @errorToInt(key)),
33 builtin.TypeId.Promise, builtin.TypeId.Fn => autoHash(hasher, @ptrToInt(key)),34 .AnyFrame, .Fn => autoHash(hasher, @ptrToInt(key)),
3435
35 builtin.TypeId.Pointer => |info| switch (info.size) {36 .Pointer => |info| switch (info.size) {
36 builtin.TypeInfo.Pointer.Size.One,37 builtin.TypeInfo.Pointer.Size.One,
37 builtin.TypeInfo.Pointer.Size.Many,38 builtin.TypeInfo.Pointer.Size.Many,
38 builtin.TypeInfo.Pointer.Size.C,39 builtin.TypeInfo.Pointer.Size.C,
...@@ -44,9 +45,9 @@ pub fn autoHash(hasher: var, key: var) void {...@@ -44,9 +45,9 @@ pub fn autoHash(hasher: var, key: var) void {
44 },45 },
45 },46 },
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 => {
50 // TODO detect via a trait when Key has no padding bits to51 // TODO detect via a trait when Key has no padding bits to
51 // hash it as an array of bytes.52 // hash it as an array of bytes.
52 // Otherwise, hash every element.53 // Otherwise, hash every element.
...@@ -55,7 +56,7 @@ pub fn autoHash(hasher: var, key: var) void {...@@ -55,7 +56,7 @@ pub fn autoHash(hasher: var, key: var) void {
55 }56 }
56 },57 },
5758
58 builtin.TypeId.Vector => |info| {59 .Vector => |info| {
59 if (info.child.bit_count % 8 == 0) {60 if (info.child.bit_count % 8 == 0) {
60 // If there's no unused bits in the child type, we can just hash61 // If there's no unused bits in the child type, we can just hash
61 // this as an array of bytes.62 // this as an array of bytes.
...@@ -71,7 +72,7 @@ pub fn autoHash(hasher: var, key: var) void {...@@ -71,7 +72,7 @@ pub fn autoHash(hasher: var, key: var) void {
71 }72 }
72 },73 },
7374
74 builtin.TypeId.Struct => |info| {75 .Struct => |info| {
75 // TODO detect via a trait when Key has no padding bits to76 // TODO detect via a trait when Key has no padding bits to
76 // hash it as an array of bytes.77 // hash it as an array of bytes.
77 // Otherwise, hash every field.78 // Otherwise, hash every field.
...@@ -82,7 +83,7 @@ pub fn autoHash(hasher: var, key: var) void {...@@ -82,7 +83,7 @@ pub fn autoHash(hasher: var, key: var) void {
82 }83 }
83 },84 },
8485
85 builtin.TypeId.Union => |info| blk: {86 .Union => |info| blk: {
86 if (info.tag_type) |tag_type| {87 if (info.tag_type) |tag_type| {
87 const tag = meta.activeTag(key);88 const tag = meta.activeTag(key);
88 const s = autoHash(hasher, tag);89 const s = autoHash(hasher, tag);
...@@ -99,7 +100,7 @@ pub fn autoHash(hasher: var, key: var) void {...@@ -99,7 +100,7 @@ pub fn autoHash(hasher: var, key: var) void {
99 } else @compileError("cannot hash untagged union type: " ++ @typeName(Key) ++ ", provide your own hash function");100 } else @compileError("cannot hash untagged union type: " ++ @typeName(Key) ++ ", provide your own hash function");
100 },101 },
101102
102 builtin.TypeId.ErrorUnion => blk: {103 .ErrorUnion => blk: {
103 const payload = key catch |err| {104 const payload = key catch |err| {
104 autoHash(hasher, err);105 autoHash(hasher, err);
105 break :blk;106 break :blk;
std/meta.zig+1-3
...@@ -104,8 +104,7 @@ pub fn Child(comptime T: type) type {...@@ -104,8 +104,7 @@ pub fn Child(comptime T: type) type {
104 TypeId.Array => |info| info.child,104 TypeId.Array => |info| info.child,
105 TypeId.Pointer => |info| info.child,105 TypeId.Pointer => |info| info.child,
106 TypeId.Optional => |info| info.child,106 TypeId.Optional => |info| info.child,
107 TypeId.Promise => |info| if (info.child) |child| child else null,107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
108 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
109 };108 };
110}109}
111110
...@@ -114,7 +113,6 @@ test "std.meta.Child" {...@@ -114,7 +113,6 @@ test "std.meta.Child" {
114 testing.expect(Child(*u8) == u8);113 testing.expect(Child(*u8) == u8);
115 testing.expect(Child([]u8) == u8);114 testing.expect(Child([]u8) == u8);
116 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
117 testing.expect(Child(promise->u8) == u8);
118}116}
119117
120pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {118pub 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 {...@@ -25,36 +25,37 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
25/// The types must match exactly.25/// The types must match exactly.
26pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {26pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
27 switch (@typeInfo(@typeOf(actual))) {27 switch (@typeInfo(@typeOf(actual))) {
28 TypeId.NoReturn,28 .NoReturn,
29 TypeId.BoundFn,29 .BoundFn,
30 TypeId.ArgTuple,30 .ArgTuple,
31 TypeId.Opaque,31 .Opaque,
32 .Frame,
33 .AnyFrame,
32 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),34 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
3335
34 TypeId.Undefined,36 .Undefined,
35 TypeId.Null,37 .Null,
36 TypeId.Void,38 .Void,
37 => return,39 => return,
3840
39 TypeId.Type,41 .Type,
40 TypeId.Bool,42 .Bool,
41 TypeId.Int,43 .Int,
42 TypeId.Float,44 .Float,
43 TypeId.ComptimeFloat,45 .ComptimeFloat,
44 TypeId.ComptimeInt,46 .ComptimeInt,
45 TypeId.EnumLiteral,47 .EnumLiteral,
46 TypeId.Enum,48 .Enum,
47 TypeId.Fn,49 .Fn,
48 TypeId.Promise,50 .Vector,
49 TypeId.Vector,51 .ErrorSet,
50 TypeId.ErrorSet,
51 => {52 => {
52 if (actual != expected) {53 if (actual != expected) {
53 std.debug.panic("expected {}, found {}", expected, actual);54 std.debug.panic("expected {}, found {}", expected, actual);
54 }55 }
55 },56 },
5657
57 TypeId.Pointer => |pointer| {58 .Pointer => |pointer| {
58 switch (pointer.size) {59 switch (pointer.size) {
59 builtin.TypeInfo.Pointer.Size.One,60 builtin.TypeInfo.Pointer.Size.One,
60 builtin.TypeInfo.Pointer.Size.Many,61 builtin.TypeInfo.Pointer.Size.Many,
...@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
76 }77 }
77 },78 },
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| {
82 inline for (structType.fields) |field| {83 inline for (structType.fields) |field| {
83 expectEqual(@field(expected, field.name), @field(actual, field.name));84 expectEqual(@field(expected, field.name), @field(actual, field.name));
84 }85 }
85 },86 },
8687
87 TypeId.Union => |union_info| {88 .Union => |union_info| {
88 if (union_info.tag_type == null) {89 if (union_info.tag_type == null) {
89 @compileError("Unable to compare untagged union values");90 @compileError("Unable to compare untagged union values");
90 }91 }
91 @compileError("TODO implement testing.expectEqual for tagged unions");92 @compileError("TODO implement testing.expectEqual for tagged unions");
92 },93 },
9394
94 TypeId.Optional => {95 .Optional => {
95 if (expected) |expected_payload| {96 if (expected) |expected_payload| {
96 if (actual) |actual_payload| {97 if (actual) |actual_payload| {
97 expectEqual(expected_payload, actual_payload);98 expectEqual(expected_payload, actual_payload);
...@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
105 }106 }
106 },107 },
107108
108 TypeId.ErrorUnion => {109 .ErrorUnion => {
109 if (expected) |expected_payload| {110 if (expected) |expected_payload| {
110 if (actual) |actual_payload| {111 if (actual) |actual_payload| {
111 expectEqual(expected_payload, actual_payload);112 expectEqual(expected_payload, actual_payload);
std/zig/ast.zig+8-8
...@@ -400,7 +400,7 @@ pub const Node = struct {...@@ -400,7 +400,7 @@ pub const Node = struct {
400 VarType,400 VarType,
401 ErrorType,401 ErrorType,
402 FnProto,402 FnProto,
403 PromiseType,403 AnyFrameType,
404404
405 // Primary expressions405 // Primary expressions
406 IntegerLiteral,406 IntegerLiteral,
...@@ -952,9 +952,9 @@ pub const Node = struct {...@@ -952,9 +952,9 @@ pub const Node = struct {
952 }952 }
953 };953 };
954954
955 pub const PromiseType = struct {955 pub const AnyFrameType = struct {
956 base: Node,956 base: Node,
957 promise_token: TokenIndex,957 anyframe_token: TokenIndex,
958 result: ?Result,958 result: ?Result,
959959
960 pub const Result = struct {960 pub const Result = struct {
...@@ -962,7 +962,7 @@ pub const Node = struct {...@@ -962,7 +962,7 @@ pub const Node = struct {
962 return_type: *Node,962 return_type: *Node,
963 };963 };
964964
965 pub fn iterate(self: *PromiseType, index: usize) ?*Node {965 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
966 var i = index;966 var i = index;
967967
968 if (self.result) |result| {968 if (self.result) |result| {
...@@ -973,13 +973,13 @@ pub const Node = struct {...@@ -973,13 +973,13 @@ pub const Node = struct {
973 return null;973 return null;
974 }974 }
975975
976 pub fn firstToken(self: *const PromiseType) TokenIndex {976 pub fn firstToken(self: *const AnyFrameType) TokenIndex {
977 return self.promise_token;977 return self.anyframe_token;
978 }978 }
979979
980 pub fn lastToken(self: *const PromiseType) TokenIndex {980 pub fn lastToken(self: *const AnyFrameType) TokenIndex {
981 if (self.result) |result| return result.return_type.lastToken();981 if (self.result) |result| return result.return_type.lastToken();
982 return self.promise_token;982 return self.anyframe_token;
983 }983 }
984 };984 };
985985
std/zig/parse.zig+20-35
...@@ -814,7 +814,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -814,7 +814,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
814/// <- AsmExpr814/// <- AsmExpr
815/// / IfExpr815/// / IfExpr
816/// / KEYWORD_break BreakLabel? Expr?816/// / KEYWORD_break BreakLabel? Expr?
817/// / KEYWORD_cancel Expr
818/// / KEYWORD_comptime Expr817/// / KEYWORD_comptime Expr
819/// / KEYWORD_continue BreakLabel?818/// / KEYWORD_continue BreakLabel?
820/// / KEYWORD_resume Expr819/// / KEYWORD_resume Expr
...@@ -839,20 +838,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -839,20 +838,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
839 return &node.base;838 return &node.base;
840 }839 }
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
856 if (eatToken(it, .Keyword_comptime)) |token| {841 if (eatToken(it, .Keyword_comptime)) |token| {
857 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{842 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
858 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },843 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
...@@ -1201,7 +1186,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1201,7 +1186,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1201/// / KEYWORD_error DOT IDENTIFIER1186/// / KEYWORD_error DOT IDENTIFIER
1202/// / KEYWORD_false1187/// / KEYWORD_false
1203/// / KEYWORD_null1188/// / KEYWORD_null
1204/// / KEYWORD_promise1189/// / KEYWORD_anyframe
1205/// / KEYWORD_true1190/// / KEYWORD_true
1206/// / KEYWORD_undefined1191/// / KEYWORD_undefined
1207/// / KEYWORD_unreachable1192/// / KEYWORD_unreachable
...@@ -1256,11 +1241,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N...@@ -1256,11 +1241,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1256 }1241 }
1257 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);1242 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1258 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);1243 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1259 if (eatToken(it, .Keyword_promise)) |token| {1244 if (eatToken(it, .Keyword_anyframe)) |token| {
1260 const node = try arena.create(Node.PromiseType);1245 const node = try arena.create(Node.AnyFrameType);
1261 node.* = Node.PromiseType{1246 node.* = Node.AnyFrameType{
1262 .base = Node{ .id = .PromiseType },1247 .base = Node{ .id = .AnyFrameType },
1263 .promise_token = token,1248 .anyframe_token = token,
1264 .result = null,1249 .result = null,
1265 };1250 };
1266 return &node.base;1251 return &node.base;
...@@ -2194,7 +2179,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2194,7 +2179,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
21942179
2195/// PrefixTypeOp2180/// PrefixTypeOp
2196/// <- QUESTIONMARK2181/// <- QUESTIONMARK
2197/// / KEYWORD_promise MINUSRARROW2182/// / KEYWORD_anyframe MINUSRARROW
2198/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2183/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2199/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2184/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2200fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2185fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
...@@ -2209,20 +2194,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2209,20 +2194,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2209 return &node.base;2194 return &node.base;
2210 }2195 }
22112196
2212 // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or2197 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2213 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).2198 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2214 // Consider making the PromiseType a member of PrefixOp and add a2199 // Consider making the AnyFrameType a member of PrefixOp and add a
2215 // PrefixOp.PromiseType variant?2200 // PrefixOp.AnyFrameType variant?
2216 if (eatToken(it, .Keyword_promise)) |token| {2201 if (eatToken(it, .Keyword_anyframe)) |token| {
2217 const arrow = eatToken(it, .Arrow) orelse {2202 const arrow = eatToken(it, .Arrow) orelse {
2218 putBackToken(it, token);2203 putBackToken(it, token);
2219 return null;2204 return null;
2220 };2205 };
2221 const node = try arena.create(Node.PromiseType);2206 const node = try arena.create(Node.AnyFrameType);
2222 node.* = Node.PromiseType{2207 node.* = Node.AnyFrameType{
2223 .base = Node{ .id = .PromiseType },2208 .base = Node{ .id = .AnyFrameType },
2224 .promise_token = token,2209 .anyframe_token = token,
2225 .result = Node.PromiseType.Result{2210 .result = Node.AnyFrameType.Result{
2226 .arrow_token = arrow,2211 .arrow_token = arrow,
2227 .return_type = undefined, // set by caller2212 .return_type = undefined, // set by caller
2228 },2213 },
...@@ -2903,8 +2888,8 @@ fn parsePrefixOpExpr(...@@ -2903,8 +2888,8 @@ fn parsePrefixOpExpr(
2903 rightmost_op = rhs;2888 rightmost_op = rhs;
2904 } else break;2889 } else break;
2905 },2890 },
2906 .PromiseType => {2891 .AnyFrameType => {
2907 const prom = rightmost_op.cast(Node.PromiseType).?;2892 const prom = rightmost_op.cast(Node.AnyFrameType).?;
2908 if (try opParseFn(arena, it, tree)) |rhs| {2893 if (try opParseFn(arena, it, tree)) |rhs| {
2909 prom.result.?.return_type = rhs;2894 prom.result.?.return_type = rhs;
2910 rightmost_op = rhs;2895 rightmost_op = rhs;
...@@ -2922,8 +2907,8 @@ fn parsePrefixOpExpr(...@@ -2922,8 +2907,8 @@ fn parsePrefixOpExpr(
2922 .InvalidToken = AstError.InvalidToken{ .token = it.index },2907 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2923 });2908 });
2924 },2909 },
2925 .PromiseType => {2910 .AnyFrameType => {
2926 const prom = rightmost_op.cast(Node.PromiseType).?;2911 const prom = rightmost_op.cast(Node.AnyFrameType).?;
2927 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{2912 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
2928 .InvalidToken = AstError.InvalidToken{ .token = it.index },2913 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2929 });2914 });
std/zig/parser_test.zig+6-6
...@@ -1183,7 +1183,7 @@ test "zig fmt: resume from suspend block" {...@@ -1183,7 +1183,7 @@ test "zig fmt: resume from suspend block" {
1183 try testCanonical(1183 try testCanonical(
1184 \\fn foo() void {1184 \\fn foo() void {
1185 \\ suspend {1185 \\ suspend {
1186 \\ resume @handle();1186 \\ resume @frame();
1187 \\ }1187 \\ }
1188 \\}1188 \\}
1189 \\1189 \\
...@@ -2103,7 +2103,7 @@ test "zig fmt: inline asm" {...@@ -2103,7 +2103,7 @@ test "zig fmt: inline asm" {
2103 );2103 );
2104}2104}
21052105
2106test "zig fmt: coroutines" {2106test "zig fmt: async functions" {
2107 try testCanonical(2107 try testCanonical(
2108 \\async fn simpleAsyncFn() void {2108 \\async fn simpleAsyncFn() void {
2109 \\ const a = async a.b();2109 \\ const a = async a.b();
...@@ -2111,14 +2111,14 @@ test "zig fmt: coroutines" {...@@ -2111,14 +2111,14 @@ test "zig fmt: coroutines" {
2111 \\ suspend;2111 \\ suspend;
2112 \\ x += 1;2112 \\ x += 1;
2113 \\ suspend;2113 \\ suspend;
2114 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;2114 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
2115 \\ await p;2115 \\ await p;
2116 \\}2116 \\}
2117 \\2117 \\
2118 \\test "coroutine suspend, resume, cancel" {2118 \\test "suspend, resume, await" {
2119 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();2119 \\ const p: anyframe = async testAsyncSeq();
2120 \\ resume p;2120 \\ resume p;
2121 \\ cancel p;2121 \\ await p;
2122 \\}2122 \\}
2123 \\2123 \\
2124 );2124 );
std/zig/render.zig+5-5
...@@ -1205,15 +1205,15 @@ fn renderExpression(...@@ -1205,15 +1205,15 @@ fn renderExpression(
1205 }1205 }
1206 },1206 },
12071207
1208 ast.Node.Id.PromiseType => {1208 ast.Node.Id.AnyFrameType => {
1209 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);1209 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
12101210
1211 if (promise_type.result) |result| {1211 if (anyframe_type.result) |result| {
1212 try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise1212 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
1213 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->1213 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
1214 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);1214 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
1215 } else {1215 } else {
1216 return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise1216 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
1217 }1217 }
1218 },1218 },
12191219
std/zig/tokenizer.zig+2-4
...@@ -15,12 +15,12 @@ pub const Token = struct {...@@ -15,12 +15,12 @@ pub const Token = struct {
15 Keyword{ .bytes = "align", .id = Id.Keyword_align },15 Keyword{ .bytes = "align", .id = Id.Keyword_align },
16 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },16 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
17 Keyword{ .bytes = "and", .id = Id.Keyword_and },17 Keyword{ .bytes = "and", .id = Id.Keyword_and },
18 Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
18 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },19 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
19 Keyword{ .bytes = "async", .id = Id.Keyword_async },20 Keyword{ .bytes = "async", .id = Id.Keyword_async },
20 Keyword{ .bytes = "await", .id = Id.Keyword_await },21 Keyword{ .bytes = "await", .id = Id.Keyword_await },
21 Keyword{ .bytes = "break", .id = Id.Keyword_break },22 Keyword{ .bytes = "break", .id = Id.Keyword_break },
22 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },23 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
23 Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel },
24 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },24 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
25 Keyword{ .bytes = "const", .id = Id.Keyword_const },25 Keyword{ .bytes = "const", .id = Id.Keyword_const },
26 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },26 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
...@@ -42,7 +42,6 @@ pub const Token = struct {...@@ -42,7 +42,6 @@ pub const Token = struct {
42 Keyword{ .bytes = "or", .id = Id.Keyword_or },42 Keyword{ .bytes = "or", .id = Id.Keyword_or },
43 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },43 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
44 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },44 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
45 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
46 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },45 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
47 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },46 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
48 Keyword{ .bytes = "return", .id = Id.Keyword_return },47 Keyword{ .bytes = "return", .id = Id.Keyword_return },
...@@ -151,7 +150,6 @@ pub const Token = struct {...@@ -151,7 +150,6 @@ pub const Token = struct {
151 Keyword_async,150 Keyword_async,
152 Keyword_await,151 Keyword_await,
153 Keyword_break,152 Keyword_break,
154 Keyword_cancel,
155 Keyword_catch,153 Keyword_catch,
156 Keyword_comptime,154 Keyword_comptime,
157 Keyword_const,155 Keyword_const,
...@@ -174,7 +172,7 @@ pub const Token = struct {...@@ -174,7 +172,7 @@ pub const Token = struct {
174 Keyword_or,172 Keyword_or,
175 Keyword_orelse,173 Keyword_orelse,
176 Keyword_packed,174 Keyword_packed,
177 Keyword_promise,175 Keyword_anyframe,
178 Keyword_pub,176 Keyword_pub,
179 Keyword_resume,177 Keyword_resume,
180 Keyword_return,178 Keyword_return,
test/compile_errors.zig+122-27
...@@ -2,6 +2,118 @@ const tests = @import("tests.zig");...@@ -2,6 +2,118 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub 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
5 cases.add(117 cases.add(
6 "capture group on switch prong with incompatible payload types",118 "capture group on switch prong with incompatible payload types",
7 \\const Union = union(enum) {119 \\const Union = union(enum) {
...@@ -1319,24 +1431,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1319,24 +1431,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1319 );1431 );
13201432
1321 cases.add(1433 cases.add(
1322 "@handle() called outside of function definition",1434 "@frame() called outside of function definition",
1323 \\var handle_undef: promise = undefined;1435 \\var handle_undef: anyframe = undefined;
1324 \\var handle_dummy: promise = @handle();1436 \\var handle_dummy: anyframe = @frame();
1325 \\export fn entry() bool {1437 \\export fn entry() bool {
1326 \\ return handle_undef == handle_dummy;1438 \\ return handle_undef == handle_dummy;
1327 \\}1439 \\}
1328 ,1440 ,
1329 "tmp.zig:2:29: error: @handle() called outside of function definition",1441 "tmp.zig:2:30: error: @frame() 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",
1340 );1442 );
13411443
1342 cases.add(1444 cases.add(
...@@ -1712,15 +1814,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1712,15 +1814,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17121814
1713 cases.add(1815 cases.add(
1714 "suspend inside suspend block",1816 "suspend inside suspend block",
1715 \\const std = @import("std",);
1716 \\
1717 \\export fn entry() void {1817 \\export fn entry() void {
1718 \\ var buf: [500]u8 = undefined;1818 \\ _ = async foo();
1719 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
1720 \\ const p = (async<a> foo()) catch unreachable;
1721 \\ cancel p;
1722 \\}1819 \\}
1723 \\
1724 \\async fn foo() void {1820 \\async fn foo() void {
1725 \\ suspend {1821 \\ suspend {
1726 \\ suspend {1822 \\ suspend {
...@@ -1728,8 +1824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1728,8 +1824,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1728 \\ }1824 \\ }
1729 \\}1825 \\}
1730 ,1826 ,
1731 "tmp.zig:12:9: error: cannot suspend inside suspend block",1827 "tmp.zig:6:9: error: cannot suspend inside suspend block",
1732 "tmp.zig:11:5: note: other suspend block here",1828 "tmp.zig:5:5: note: other suspend block here",
1733 );1829 );
17341830
1735 cases.add(1831 cases.add(
...@@ -1770,15 +1866,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1770,15 +1866,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17701866
1771 cases.add(1867 cases.add(
1772 "returning error from void async function",1868 "returning error from void async function",
1773 \\const std = @import("std",);
1774 \\export fn entry() void {1869 \\export fn entry() void {
1775 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;1870 \\ _ = async amain();
1776 \\}1871 \\}
1777 \\async fn amain() void {1872 \\async fn amain() void {
1778 \\ return error.ShouldBeCompileError;1873 \\ return error.ShouldBeCompileError;
1779 \\}1874 \\}
1780 ,1875 ,
1781 "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",1876 "tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
1782 );1877 );
17831878
1784 cases.add(1879 cases.add(
...@@ -3307,7 +3402,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3307,7 +3402,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3307 \\3402 \\
3308 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }3403 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
3309 ,3404 ,
3310 "tmp.zig:5:18: error: unable to evaluate constant expression",3405 "tmp.zig:5:25: error: unable to evaluate constant expression",
3311 "tmp.zig:2:12: note: called from here",3406 "tmp.zig:2:12: note: called from here",
3312 "tmp.zig:2:8: note: called from here",3407 "tmp.zig:2:8: note: called from here",
3313 );3408 );
test/runtime_safety.zig+96-5
...@@ -1,6 +1,91 @@...@@ -1,6 +1,91 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub 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
4 cases.addRuntimeSafety(".? operator on null pointer",89 cases.addRuntimeSafety(".? operator on null pointer",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {90 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);91 \\ @import("std").os.exit(126);
...@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
483 \\ std.os.exit(126);568 \\ std.os.exit(126);
484 \\}569 \\}
485 \\570 \\
571 \\var failing_frame: @Frame(failing) = undefined;
572 \\
486 \\pub fn main() void {573 \\pub fn main() void {
487 \\ const p = nonFailing();574 \\ const p = nonFailing();
488 \\ resume p;575 \\ resume p;
489 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;576 \\ const p2 = async printTrace(p);
490 \\ cancel p2;
491 \\}577 \\}
492 \\578 \\
493 \\fn nonFailing() promise->anyerror!void {579 \\fn nonFailing() anyframe->anyerror!void {
494 \\ return async<std.debug.global_allocator> failing() catch unreachable;580 \\ failing_frame = async failing();
581 \\ return &failing_frame;
495 \\}582 \\}
496 \\583 \\
497 \\async fn failing() anyerror!void {584 \\async fn failing() anyerror!void {
498 \\ suspend;585 \\ suspend;
586 \\ return second();
587 \\}
588 \\
589 \\async fn second() anyerror!void {
499 \\ return error.Fail;590 \\ return error.Fail;
500 \\}591 \\}
501 \\592 \\
502 \\async fn printTrace(p: promise->anyerror!void) void {593 \\async fn printTrace(p: anyframe->anyerror!void) void {
503 \\ (await p) catch unreachable;594 \\ (await p) catch unreachable;
504 \\}595 \\}
505 );596 );
test/stage1/behavior.zig+6-7
...@@ -3,12 +3,13 @@ comptime {...@@ -3,12 +3,13 @@ comptime {
3 _ = @import("behavior/alignof.zig");3 _ = @import("behavior/alignof.zig");
4 _ = @import("behavior/array.zig");4 _ = @import("behavior/array.zig");
5 _ = @import("behavior/asm.zig");5 _ = @import("behavior/asm.zig");
6 _ = @import("behavior/async_fn.zig");
6 _ = @import("behavior/atomics.zig");7 _ = @import("behavior/atomics.zig");
8 _ = @import("behavior/await_struct.zig");
7 _ = @import("behavior/bit_shifting.zig");9 _ = @import("behavior/bit_shifting.zig");
8 _ = @import("behavior/bitcast.zig");10 _ = @import("behavior/bitcast.zig");
9 _ = @import("behavior/bitreverse.zig");11 _ = @import("behavior/bitreverse.zig");
10 _ = @import("behavior/bool.zig");12 _ = @import("behavior/bool.zig");
11 _ = @import("behavior/byteswap.zig");
12 _ = @import("behavior/bugs/1025.zig");13 _ = @import("behavior/bugs/1025.zig");
13 _ = @import("behavior/bugs/1076.zig");14 _ = @import("behavior/bugs/1076.zig");
14 _ = @import("behavior/bugs/1111.zig");15 _ = @import("behavior/bugs/1111.zig");
...@@ -38,23 +39,23 @@ comptime {...@@ -38,23 +39,23 @@ comptime {
38 _ = @import("behavior/bugs/726.zig");39 _ = @import("behavior/bugs/726.zig");
39 _ = @import("behavior/bugs/828.zig");40 _ = @import("behavior/bugs/828.zig");
40 _ = @import("behavior/bugs/920.zig");41 _ = @import("behavior/bugs/920.zig");
42 _ = @import("behavior/byteswap.zig");
41 _ = @import("behavior/byval_arg_var.zig");43 _ = @import("behavior/byval_arg_var.zig");
42 _ = @import("behavior/cancel.zig");
43 _ = @import("behavior/cast.zig");44 _ = @import("behavior/cast.zig");
44 _ = @import("behavior/const_slice_child.zig");45 _ = @import("behavior/const_slice_child.zig");
45 _ = @import("behavior/coroutine_await_struct.zig");
46 _ = @import("behavior/coroutines.zig");
47 _ = @import("behavior/defer.zig");46 _ = @import("behavior/defer.zig");
48 _ = @import("behavior/enum.zig");47 _ = @import("behavior/enum.zig");
49 _ = @import("behavior/enum_with_members.zig");48 _ = @import("behavior/enum_with_members.zig");
50 _ = @import("behavior/error.zig");49 _ = @import("behavior/error.zig");
51 _ = @import("behavior/eval.zig");50 _ = @import("behavior/eval.zig");
52 _ = @import("behavior/field_parent_ptr.zig");51 _ = @import("behavior/field_parent_ptr.zig");
52 _ = @import("behavior/floatop.zig");
53 _ = @import("behavior/fn.zig");53 _ = @import("behavior/fn.zig");
54 _ = @import("behavior/fn_in_struct_in_comptime.zig");54 _ = @import("behavior/fn_in_struct_in_comptime.zig");
55 _ = @import("behavior/for.zig");55 _ = @import("behavior/for.zig");
56 _ = @import("behavior/generics.zig");56 _ = @import("behavior/generics.zig");
57 _ = @import("behavior/hasdecl.zig");57 _ = @import("behavior/hasdecl.zig");
58 _ = @import("behavior/hasfield.zig");
58 _ = @import("behavior/if.zig");59 _ = @import("behavior/if.zig");
59 _ = @import("behavior/import.zig");60 _ = @import("behavior/import.zig");
60 _ = @import("behavior/incomplete_struct_param_tld.zig");61 _ = @import("behavior/incomplete_struct_param_tld.zig");
...@@ -63,14 +64,13 @@ comptime {...@@ -63,14 +64,13 @@ comptime {
63 _ = @import("behavior/math.zig");64 _ = @import("behavior/math.zig");
64 _ = @import("behavior/merge_error_sets.zig");65 _ = @import("behavior/merge_error_sets.zig");
65 _ = @import("behavior/misc.zig");66 _ = @import("behavior/misc.zig");
67 _ = @import("behavior/muladd.zig");
66 _ = @import("behavior/namespace_depends_on_compile_var.zig");68 _ = @import("behavior/namespace_depends_on_compile_var.zig");
67 _ = @import("behavior/new_stack_call.zig");69 _ = @import("behavior/new_stack_call.zig");
68 _ = @import("behavior/null.zig");70 _ = @import("behavior/null.zig");
69 _ = @import("behavior/optional.zig");71 _ = @import("behavior/optional.zig");
70 _ = @import("behavior/pointers.zig");72 _ = @import("behavior/pointers.zig");
71 _ = @import("behavior/popcount.zig");73 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
74 _ = @import("behavior/ptrcast.zig");74 _ = @import("behavior/ptrcast.zig");
75 _ = @import("behavior/pub_enum.zig");75 _ = @import("behavior/pub_enum.zig");
76 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");76 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
...@@ -99,5 +99,4 @@ comptime {...@@ -99,5 +99,4 @@ comptime {
99 _ = @import("behavior/void.zig");99 _ = @import("behavior/void.zig");
100 _ = @import("behavior/while.zig");100 _ = @import("behavior/while.zig");
101 _ = @import("behavior/widening.zig");101 _ = @import("behavior/widening.zig");
102 _ = @import("behavior/hasfield.zig");
103}102}
test/stage1/behavior/align.zig+62
...@@ -228,3 +228,65 @@ test "alignment of extern() void" {...@@ -228,3 +228,65 @@ test "alignment of extern() void" {
228}228}
229229
230extern fn nothing() void {}230extern 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 {...@@ -116,21 +116,6 @@ fn testOptional() void {
116 expect(null_info.Optional.child == void);116 expect(null_info.Optional.child == void);
117}117}
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
134test "type info: error set, error union info" {119test "type info: error set, error union info" {
135 testErrorSet();120 testErrorSet();
136 comptime testErrorSet();121 comptime testErrorSet();
...@@ -192,7 +177,7 @@ fn testUnion() void {...@@ -192,7 +177,7 @@ fn testUnion() void {
192 expect(TypeId(typeinfo_info) == TypeId.Union);177 expect(TypeId(typeinfo_info) == TypeId.Union);
193 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);178 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
194 expect(typeinfo_info.Union.tag_type.? == TypeId);179 expect(typeinfo_info.Union.tag_type.? == TypeId);
195 expect(typeinfo_info.Union.fields.len == 25);180 expect(typeinfo_info.Union.fields.len == 26);
196 expect(typeinfo_info.Union.fields[4].enum_field != null);181 expect(typeinfo_info.Union.fields[4].enum_field != null);
197 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);182 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
198 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));183 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
...@@ -265,7 +250,6 @@ fn testFunction() void {...@@ -265,7 +250,6 @@ fn testFunction() void {
265 expect(fn_info.Fn.args.len == 2);250 expect(fn_info.Fn.args.len == 2);
266 expect(fn_info.Fn.is_var_args);251 expect(fn_info.Fn.is_var_args);
267 expect(fn_info.Fn.return_type == null);252 expect(fn_info.Fn.return_type == null);
268 expect(fn_info.Fn.async_allocator_type == null);
269253
270 const test_instance: TestStruct = undefined;254 const test_instance: TestStruct = undefined;
271 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));255 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
...@@ -296,6 +280,25 @@ fn testVector() void {...@@ -296,6 +280,25 @@ fn testVector() void {
296 expect(vec_info.Vector.child == i32);280 expect(vec_info.Vector.child == i32);
297}281}
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
299test "type info: optional field unwrapping" {302test "type info: optional field unwrapping" {
300 const Struct = struct {303 const Struct = struct {
301 cdOffset: u32,304 cdOffset: u32,