authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-16 16:43:56-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-16 16:43:56-04:00
log6529658ad861bc47e9641081bb953ba54f21a1ae
tree3835b552e9eac3499a6e04cbcd28d42a10febbd5
parent5ce1a965e02b45a9b3bcb0328f40e08c5585e1e3
parentbf7b6fbbdb7d28c0d7dba3e17c46ce156712cfc8
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm9


82 files changed, 6809 insertions(+), 5516 deletions(-)

CMakeLists.txt+7-7
......@@ -202,11 +202,11 @@ else()
202202 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Writer.cpp"
203203 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/WriterUtils.cpp"
204204 )
205 add_library(embedded_lld_lib ${EMBEDDED_LLD_LIB_SOURCES})
206 add_library(embedded_lld_elf ${EMBEDDED_LLD_ELF_SOURCES})
207 add_library(embedded_lld_coff ${EMBEDDED_LLD_COFF_SOURCES})
208 add_library(embedded_lld_mingw ${EMBEDDED_LLD_MINGW_SOURCES})
209 add_library(embedded_lld_wasm ${EMBEDDED_LLD_WASM_SOURCES})
205 add_library(embedded_lld_lib STATIC ${EMBEDDED_LLD_LIB_SOURCES})
206 add_library(embedded_lld_elf STATIC ${EMBEDDED_LLD_ELF_SOURCES})
207 add_library(embedded_lld_coff STATIC ${EMBEDDED_LLD_COFF_SOURCES})
208 add_library(embedded_lld_mingw STATIC ${EMBEDDED_LLD_MINGW_SOURCES})
209 add_library(embedded_lld_wasm STATIC ${EMBEDDED_LLD_WASM_SOURCES})
210210 if(MSVC)
211211 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
212212 else()
......@@ -403,7 +403,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
403403 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"
404404 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c"
405405)
406add_library(embedded_softfloat ${EMBEDDED_SOFTFLOAT_SOURCES})
406add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES})
407407if(MSVC)
408408 set_target_properties(embedded_softfloat PROPERTIES
409409 COMPILE_FLAGS "-std=c99 /w"
......@@ -429,7 +429,6 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
429429set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")
430430
431431set(ZIG_SOURCES
432 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
433432 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
434433 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
435434 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
......@@ -441,6 +440,7 @@ set(ZIG_SOURCES
441440 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"
442441 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
443442 "${CMAKE_SOURCE_DIR}/src/error.cpp"
443 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
444444 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
445445 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
446446 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
CONTRIBUTING.md+6-6
......@@ -25,6 +25,7 @@ Here are some examples:
2525
2626 * [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html)
2727 * [The Right Tool for the Right Job: Redis Modules & Zig](https://www.youtube.com/watch?v=eCHM8-_poZY)
28 * [Writing a small ray tracer in Rust and Zig](https://nelari.us/post/raytracer_with_rust_and_zig/)
2829
2930Zig is a brand new language, with no advertising budget. Word of mouth is the
3031only way people find out about the project, and the more people hear about it,
......@@ -45,8 +46,8 @@ The most highly regarded argument in such a discussion is a real world use case.
4546
4647The issue label
4748[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22)
48exists to help contributors find issues that are "limited in scope and/or
49knowledge of Zig internals."
49exists to help you find issues that are **limited in scope and/or
50knowledge of Zig internals.**
5051
5152### Editing Source Code
5253
......@@ -61,8 +62,7 @@ To test changes, do the following from the build directory:
6162
62631. Run `make install` (on POSIX) or
6364 `msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
642. `bin/zig build --build-file ../build.zig test` (on POSIX) or
65 `bin\zig.exe build --build-file ..\build.zig test` (on Windows).
652. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
6666
6767That runs the whole test suite, which does a lot of extra testing that you
6868likely won't always need, and can take upwards of 2 hours. This is what the
......@@ -79,8 +79,8 @@ Another example is choosing a different set of things to test. For example,
7979not the other ones. Combining this suggestion with the previous one, you could
8080do this:
8181
82`bin/zig build --build-file ../build.zig test-std -Dskip-release` (on POSIX) or
83`bin\zig.exe build --build-file ..\build.zig test-std -Dskip-release` (on Windows).
82`bin/zig build test-std -Dskip-release` (on POSIX) or
83`bin\zig.exe build test-std -Dskip-release` (on Windows).
8484
8585This will run only the standard library tests, in debug mode only, for all
8686targets (it will cross-compile the tests for non-native targets but not run
README.md+2-1
......@@ -1,6 +1,6 @@
11![ZIG](https://ziglang.org/zig-logo.svg)
22
3Zig is an open-source programming language designed for **robustness**,
3A general-purpose programming language designed for **robustness**,
44**optimality**, and **maintainability**.
55
66## Resources
......@@ -10,6 +10,7 @@ Zig is an open-source programming language designed for **robustness**,
1010 * [Community](https://github.com/ziglang/zig/wiki/Community)
1111 * [Contributing](https://github.com/ziglang/zig/blob/master/CONTRIBUTING.md)
1212 * [Frequently Asked Questions](https://github.com/ziglang/zig/wiki/FAQ)
13 * [Community Projects](https://github.com/ziglang/zig/wiki/Community-Projects)
1314
1415## Building from Source
1516
build.zig+3-1
......@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {
375375 artifact.bundle_compiler_rt = true;
376376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
377377 artifact.linkSystemLibrary("c");
378 artifact.linkSystemLibrary("ntdll");
378 if (builtin.os == .windows) {
379 artifact.linkSystemLibrary("ntdll");
380 }
379381 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
380382 libuserland_step.dependOn(&artifact.step);
381383
doc/docgen.zig+1-2
......@@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
750750 .Keyword_async,
751751 .Keyword_await,
752752 .Keyword_break,
753 .Keyword_cancel,
754753 .Keyword_catch,
755754 .Keyword_comptime,
756755 .Keyword_const,
......@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
770769 .Keyword_or,
771770 .Keyword_orelse,
772771 .Keyword_packed,
773 .Keyword_promise,
772 .Keyword_anyframe,
774773 .Keyword_pub,
775774 .Keyword_resume,
776775 .Keyword_return,
doc/langref.html.in+334-174
......@@ -5968,55 +5968,27 @@ test "global assembly" {
59685968 <p>TODO: @atomic rmw</p>
59695969 <p>TODO: builtin atomic memory ordering enum</p>
59705970 {#header_close#}
5971 {#header_open|Coroutines#}
5971 {#header_open|Async Functions#}
59725972 <p>
5973 A coroutine is a generalization of a function.
5973 When a function is called, a frame is pushed to the stack,
5974 the function runs until it reaches a return statement, and then the frame is popped from the stack.
5975 At the callsite, the following code does not run until the function returns.
59745976 </p>
59755977 <p>
5976 When you call a function, it creates a stack frame,
5977 and then the function runs until it reaches a return
5978 statement, and then the stack frame is destroyed.
5979 At the callsite, the next line of code does not run
5980 until the function returns.
5978 An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
5979 followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
5980 provided explicitly by the caller, and it can be suspended and resumed any number of times.
59815981 </p>
59825982 <p>
5983 A coroutine is like a function, but it can be suspended
5984 and resumed any number of times, and then it must be
5985 explicitly destroyed. When a coroutine suspends, it
5986 returns to the resumer.
5987 </p>
5988 {#header_open|Minimal Coroutine Example#}
5989 <p>
5990 Declare a coroutine with the {#syntax#}async{#endsyntax#} keyword.
5991 The expression in angle brackets must evaluate to a struct
5992 which has these fields:
5993 </p>
5994 <ul>
5995 <li>{#syntax#}allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8{#endsyntax#} - where {#syntax#}Error{#endsyntax#} can be any error set.</li>
5996 <li>{#syntax#}freeFn: fn (self: *Allocator, old_mem: []u8) void{#endsyntax#}</li>
5997 </ul>
5998 <p>
5999 You may notice that this corresponds to the {#syntax#}std.mem.Allocator{#endsyntax#} interface.
6000 This makes it convenient to integrate with existing allocators. Note, however,
6001 that the language feature does not depend on the standard library, and any struct which
6002 has these fields is allowed.
6003 </p>
6004 <p>
6005 Omitting the angle bracket expression when defining an async function makes
6006 the function generic. Zig will infer the allocator type when the async function is called.
6007 </p>
6008 <p>
6009 Call a coroutine with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
6010 is a pointer to the allocator struct that the coroutine expects.
6011 </p>
6012 <p>
6013 The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
6014 is the return type of the async function. Once a promise has been created, it must be
6015 consumed, either with {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}:
5983 Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
5984 a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
5985 function call of an async function is a suspend point.
60165986 </p>
5987 {#header_open|Suspend and Resume#}
60175988 <p>
6018 Async functions start executing when created, so in the following example, the entire
6019 async function completes before it is canceled:
5989 At any point, a function may suspend itself. This causes control flow to
5990 return to the callsite (in the case of the first suspension),
5991 or resumer (in the case of subsequent suspensions).
60205992 </p>
60215993 {#code_begin|test#}
60225994const std = @import("std");
......@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;
60245996
60255997var x: i32 = 1;
60265998
6027test "create a coroutine and cancel it" {
6028 const p = try async<std.debug.global_allocator> simpleAsyncFn();
6029 comptime assert(@typeOf(p) == promise->void);
6030 cancel p;
5999test "suspend with no resume" {
6000 var frame = async func();
60316001 assert(x == 2);
60326002}
6033async<*std.mem.Allocator> fn simpleAsyncFn() void {
6034 x += 1;
6035}
6036 {#code_end#}
6037 {#header_close#}
6038 {#header_open|Suspend and Resume#}
6039 <p>
6040 At any point, an async function may suspend itself. This causes control flow to
6041 return to the caller or resumer. The following code demonstrates where control flow
6042 goes:
6043 </p>
6044 {#code_begin|test#}
6045const std = @import("std");
6046const assert = std.debug.assert;
6047
6048test "coroutine suspend, resume, cancel" {
6049 seq('a');
6050 const p = try async<std.debug.global_allocator> testAsyncSeq();
6051 seq('c');
6052 resume p;
6053 seq('f');
6054 cancel p;
6055 seq('g');
60566003
6057 assert(std.mem.eql(u8, points, "abcdefg"));
6058}
6059async fn testAsyncSeq() void {
6060 defer seq('e');
6061
6062 seq('b');
6004fn func() void {
6005 x += 1;
60636006 suspend;
6064 seq('d');
6065}
6066var points = [_]u8{0} ** "abcdefg".len;
6067var index: usize = 0;
6068
6069fn seq(c: u8) void {
6070 points[index] = c;
6071 index += 1;
6007 // This line is never reached because the suspend has no matching resume.
6008 x += 1;
60726009}
60736010 {#code_end#}
60746011 <p>
6075 When an async function suspends itself, it must be sure that it will be
6076 resumed or canceled somehow, for example by registering its promise handle
6077 in an event loop. Use a suspend capture block to gain access to the
6078 promise:
6012 In the same way that each allocation should have a corresponding free,
6013 Each {#syntax#}suspend{#endsyntax#} should have a corresponding {#syntax#}resume{#endsyntax#}.
6014 A <strong>suspend block</strong> allows a function to put a pointer to its own
6015 frame somewhere, for example into an event loop, even if that action will perform a
6016 {#syntax#}resume{#endsyntax#} operation on a different thread.
6017 {#link|@frame#} provides access to the async function frame pointer.
60796018 </p>
60806019 {#code_begin|test#}
60816020const std = @import("std");
60826021const assert = std.debug.assert;
60836022
6084test "coroutine suspend with block" {
6085 const p = try async<std.debug.global_allocator> testSuspendBlock();
6086 std.debug.assert(!result);
6087 resume a_promise;
6088 std.debug.assert(result);
6089 cancel p;
6023var the_frame: anyframe = undefined;
6024var result = false;
6025
6026test "async function suspend with block" {
6027 _ = async testSuspendBlock();
6028 assert(!result);
6029 resume the_frame;
6030 assert(result);
60906031}
60916032
6092var a_promise: promise = undefined;
6093var result = false;
6094async fn testSuspendBlock() void {
6033fn testSuspendBlock() void {
60956034 suspend {
6096 comptime assert(@typeOf(@handle()) == promise->void);
6097 a_promise = @handle();
6035 comptime assert(@typeOf(@frame()) == *@Frame(testSuspendBlock));
6036 the_frame = @frame();
60986037 }
60996038 result = true;
61006039}
61016040 {#code_end#}
61026041 <p>
6103 Every suspend point in an async function represents a point at which the coroutine
6104 could be destroyed. If that happens, {#syntax#}defer{#endsyntax#} expressions that are in
6105 scope are run, as well as {#syntax#}errdefer{#endsyntax#} expressions.
6106 </p>
6107 <p>
6108 {#link|Await#} counts as a suspend point.
6042 {#syntax#}suspend{#endsyntax#} causes a function to be {#syntax#}async{#endsyntax#}.
61096043 </p>
6044
61106045 {#header_open|Resuming from Suspend Blocks#}
61116046 <p>
6112 Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered
6047 Upon entering a {#syntax#}suspend{#endsyntax#} block, the async function is already considered
61136048 suspended, and can be resumed. For example, if you started another kernel thread,
6114 and had that thread call {#syntax#}resume{#endsyntax#} on the promise handle provided by the
6115 {#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend
6049 and had that thread call {#syntax#}resume{#endsyntax#} on the frame pointer provided by the
6050 {#link|@frame#}, the new thread would begin executing after the suspend
61166051 block, while the old thread continued executing the suspend block.
61176052 </p>
61186053 <p>
6119 However, the coroutine can be directly resumed from the suspend block, in which case it
6054 However, the async function can be directly resumed from the suspend block, in which case it
61206055 never returns to its resumer and continues executing.
61216056 </p>
61226057 {#code_begin|test#}
......@@ -6124,16 +6059,13 @@ const std = @import("std");
61246059const assert = std.debug.assert;
61256060
61266061test "resume from suspend" {
6127 var buf: [500]u8 = undefined;
6128 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
61296062 var my_result: i32 = 1;
6130 const p = try async<a> testResumeFromSuspend(&my_result);
6131 cancel p;
6063 _ = async testResumeFromSuspend(&my_result);
61326064 std.debug.assert(my_result == 2);
61336065}
6134async fn testResumeFromSuspend(my_result: *i32) void {
6066fn testResumeFromSuspend(my_result: *i32) void {
61356067 suspend {
6136 resume @handle();
6068 resume @frame();
61376069 }
61386070 my_result.* += 1;
61396071 suspend;
......@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {
61416073}
61426074 {#code_end#}
61436075 <p>
6144 This is guaranteed to be a tail call, and therefore will not cause a new stack frame.
6076 This is guaranteed to tail call, and therefore will not cause a new stack frame.
61456077 </p>
61466078 {#header_close#}
61476079 {#header_close#}
6148 {#header_open|Await#}
6080
6081 {#header_open|Async and Await#}
61496082 <p>
6150 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6151 {#syntax#}return{#endsyntax#} statement.
6083 In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
6084 {#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}.
61526085 </p>
6086 {#code_begin|test#}
6087const std = @import("std");
6088const assert = std.debug.assert;
6089
6090test "async and await" {
6091 // Here we have an exception where we do not match an async
6092 // with an await. The test block is not async and so cannot
6093 // have a suspend point in it.
6094 // This is well-defined behavior, and everything is OK here.
6095 // Note however that there would be no way to collect the
6096 // return value of amain, if it were something other than void.
6097 _ = async amain();
6098}
6099
6100fn amain() void {
6101 var frame = async func();
6102 comptime assert(@typeOf(frame) == @Frame(func));
6103
6104 const ptr: anyframe->void = &frame;
6105 const any_ptr: anyframe = ptr;
6106
6107 resume any_ptr;
6108 await ptr;
6109}
6110
6111fn func() void {
6112 suspend;
6113}
6114 {#code_end#}
61536115 <p>
6154 {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes
6155 as an operand a promise handle.
6156 If the async function associated with the promise handle has already returned,
6157 then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
6158 Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
6159 promise handle with the target coroutine. It becomes the target coroutine's responsibility
6160 to have ensured that it will be resumed or destroyed. When the target coroutine reaches
6161 its return statement, it gives the return value to the awaiter, destroys itself, and then
6162 resumes the awaiter.
6116 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6117 {#syntax#}return{#endsyntax#} statement.
61636118 </p>
61646119 <p>
6165 A promise handle must be consumed exactly once after it is created, either by {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}.
6120 {#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that
6121 implicitly casts to {#syntax#}anyframe->T{#endsyntax#}.
61666122 </p>
61676123 <p>
6168 {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},
6169 a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.
6124 There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
6125 It is the other way around: it suspends until the target function completes.
6126 In the event that the target function has already completed, {#syntax#}await{#endsyntax#}
6127 does not suspend; instead it copies the
6128 return value directly from the target function's frame.
61706129 </p>
61716130 {#code_begin|test#}
61726131const std = @import("std");
61736132const assert = std.debug.assert;
61746133
6175var a_promise: promise = undefined;
6134var the_frame: anyframe = undefined;
61766135var final_result: i32 = 0;
61776136
6178test "coroutine await" {
6137test "async function await" {
61796138 seq('a');
6180 const p = async<std.debug.global_allocator> amain() catch unreachable;
6139 _ = async amain();
61816140 seq('f');
6182 resume a_promise;
6141 resume the_frame;
61836142 seq('i');
61846143 assert(final_result == 1234);
61856144 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
61866145}
6187async fn amain() void {
6146fn amain() void {
61886147 seq('b');
6189 const p = async another() catch unreachable;
6148 var f = async another();
61906149 seq('e');
6191 final_result = await p;
6150 final_result = await f;
61926151 seq('h');
61936152}
6194async fn another() i32 {
6153fn another() i32 {
61956154 seq('c');
61966155 suspend {
61976156 seq('d');
6198 a_promise = @handle();
6157 the_frame = @frame();
61996158 }
62006159 seq('g');
62016160 return 1234;
......@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {
62116170 {#code_end#}
62126171 <p>
62136172 In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application
6214 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6215 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
6173 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6174 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
62166175 </p>
62176176 {#header_close#}
6218 {#header_open|Open Issues#}
6177
6178 {#header_open|Async Function Example#}
62196179 <p>
6220 There are a few issues with coroutines that are considered unresolved. Best be aware of them,
6221 as the situation is likely to change before 1.0.0:
6180 Putting all of this together, here is an example of typical
6181 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
6182 </p>
6183 {#code_begin|exe|async#}
6184const std = @import("std");
6185const Allocator = std.mem.Allocator;
6186
6187pub fn main() void {
6188 _ = async amainWrap();
6189
6190 // Typically we would use an event loop to manage resuming async functions,
6191 // but in this example we hard code what the event loop would do,
6192 // to make things deterministic.
6193 resume global_file_frame;
6194 resume global_download_frame;
6195}
6196
6197fn amainWrap() void {
6198 amain() catch |e| {
6199 std.debug.warn("{}\n", e);
6200 if (@errorReturnTrace()) |trace| {
6201 std.debug.dumpStackTrace(trace.*);
6202 }
6203 std.process.exit(1);
6204 };
6205}
6206
6207fn amain() !void {
6208 const allocator = std.heap.direct_allocator;
6209 var download_frame = async fetchUrl(allocator, "https://example.com/");
6210 var awaited_download_frame = false;
6211 errdefer if (!awaited_download_frame) {
6212 if (await download_frame) |r| allocator.free(r) else |_| {}
6213 };
6214
6215 var file_frame = async readFile(allocator, "something.txt");
6216 var awaited_file_frame = false;
6217 errdefer if (!awaited_file_frame) {
6218 if (await file_frame) |r| allocator.free(r) else |_| {}
6219 };
6220
6221 awaited_file_frame = true;
6222 const file_text = try await file_frame;
6223 defer allocator.free(file_text);
6224
6225 awaited_download_frame = true;
6226 const download_text = try await download_frame;
6227 defer allocator.free(download_text);
6228
6229 std.debug.warn("download_text: {}\n", download_text);
6230 std.debug.warn("file_text: {}\n", file_text);
6231}
6232
6233var global_download_frame: anyframe = undefined;
6234fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6235 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6236 errdefer allocator.free(result);
6237 suspend {
6238 global_download_frame = @frame();
6239 }
6240 std.debug.warn("fetchUrl returning\n");
6241 return result;
6242}
6243
6244var global_file_frame: anyframe = undefined;
6245fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6246 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6247 errdefer allocator.free(result);
6248 suspend {
6249 global_file_frame = @frame();
6250 }
6251 std.debug.warn("readFile returning\n");
6252 return result;
6253}
6254 {#code_end#}
6255 <p>
6256 Now we remove the {#syntax#}suspend{#endsyntax#} and {#syntax#}resume{#endsyntax#} code, and
6257 observe the same behavior, with one tiny difference:
6258 </p>
6259 {#code_begin|exe|blocking#}
6260const std = @import("std");
6261const Allocator = std.mem.Allocator;
6262
6263pub fn main() void {
6264 _ = async amainWrap();
6265}
6266
6267fn amainWrap() void {
6268 amain() catch |e| {
6269 std.debug.warn("{}\n", e);
6270 if (@errorReturnTrace()) |trace| {
6271 std.debug.dumpStackTrace(trace.*);
6272 }
6273 std.process.exit(1);
6274 };
6275}
6276
6277fn amain() !void {
6278 const allocator = std.heap.direct_allocator;
6279 var download_frame = async fetchUrl(allocator, "https://example.com/");
6280 var awaited_download_frame = false;
6281 errdefer if (!awaited_download_frame) {
6282 if (await download_frame) |r| allocator.free(r) else |_| {}
6283 };
6284
6285 var file_frame = async readFile(allocator, "something.txt");
6286 var awaited_file_frame = false;
6287 errdefer if (!awaited_file_frame) {
6288 if (await file_frame) |r| allocator.free(r) else |_| {}
6289 };
6290
6291 awaited_file_frame = true;
6292 const file_text = try await file_frame;
6293 defer allocator.free(file_text);
6294
6295 awaited_download_frame = true;
6296 const download_text = try await download_frame;
6297 defer allocator.free(download_text);
6298
6299 std.debug.warn("download_text: {}\n", download_text);
6300 std.debug.warn("file_text: {}\n", file_text);
6301}
6302
6303fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6304 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6305 errdefer allocator.free(result);
6306 std.debug.warn("fetchUrl returning\n");
6307 return result;
6308}
6309
6310fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6311 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6312 errdefer allocator.free(result);
6313 std.debug.warn("readFile returning\n");
6314 return result;
6315}
6316 {#code_end#}
6317 <p>
6318 Previously, the {#syntax#}fetchUrl{#endsyntax#} and {#syntax#}readFile{#endsyntax#} functions suspended,
6319 and were resumed in an order determined by the {#syntax#}main{#endsyntax#} function. Now,
6320 since there are no suspend points, the order of the printed "... returning" messages
6321 is determined by the order of {#syntax#}async{#endsyntax#} callsites.
62226322 </p>
6223 <ul>
6224 <li>Async functions have optimizations disabled - even in release modes - due to an
6225 <a href="https://github.com/ziglang/zig/issues/802">LLVM bug</a>.
6226 </li>
6227 <li>
6228 There are some situations where we can know statically that there will not be
6229 memory allocation failure, but Zig still forces us to handle it.
6230 TODO file an issue for this and link it here.
6231 </li>
6232 <li>
6233 Zig does not take advantage of LLVM's allocation elision optimization for
6234 coroutines. It crashed LLVM when I tried to do it the first time. This is
6235 related to the other 2 bullet points here. See
6236 <a href="https://github.com/ziglang/zig/issues/802">#802</a>.
6237 </li>
6238 </ul>
62396323 {#header_close#}
62406324
62416325 {#header_close#}
......@@ -6293,6 +6377,49 @@ comptime {
62936377 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
62946378 </p>
62956379 {#header_close#}
6380
6381 {#header_open|@asyncCall#}
6382 <pre>{#syntax#}@asyncCall(frame_buffer: []u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre>
6383 <p>
6384 {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer,
6385 which may or may not be an {#link|async function|Async Functions#}.
6386 </p>
6387 <p>
6388 The provided {#syntax#}frame_buffer{#endsyntax#} must be large enough to fit the entire function frame.
6389 This size can be determined with {#link|@frameSize#}. To provide a too-small buffer
6390 invokes safety-checked {#link|Undefined Behavior#}.
6391 </p>
6392 <p>
6393 {#syntax#}result_ptr{#endsyntax#} is optional ({#link|null#} may be provided). If provided,
6394 the function call will write its result directly to the result pointer, which will be available to
6395 read after {#link|await|Async and Await#} completes. Any result location provided to
6396 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
6397 </p>
6398 {#code_begin|test#}
6399const std = @import("std");
6400const assert = std.debug.assert;
6401
6402test "async fn pointer in a struct field" {
6403 var data: i32 = 1;
6404 const Foo = struct {
6405 bar: async fn (*i32) void,
6406 };
6407 var foo = Foo{ .bar = func };
6408 var bytes: [64]u8 = undefined;
6409 const f = @asyncCall(&bytes, {}, foo.bar, &data);
6410 assert(data == 2);
6411 resume f;
6412 assert(data == 4);
6413}
6414
6415async fn func(y: *i32) void {
6416 defer y.* += 2;
6417 y.* += 1;
6418 suspend;
6419}
6420 {#code_end#}
6421 {#header_close#}
6422
62966423 {#header_open|@atomicLoad#}
62976424 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
62986425 <p>
......@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}
68837010 {#see_also|@intToFloat#}
68847011 {#header_close#}
68857012
7013 {#header_open|@frame#}
7014 <pre>{#syntax#}@frame() *@Frame(func){#endsyntax#}</pre>
7015 <p>
7016 This function returns a pointer to the frame for a given function. This type
7017 can be {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyframe->T{#endsyntax#} and
7018 to {#syntax#}anyframe{#endsyntax#}, where {#syntax#}T{#endsyntax#} is the return type
7019 of the function in scope.
7020 </p>
7021 <p>
7022 This function does not mark a suspension point, but it does cause the function in scope
7023 to become an {#link|async function|Async Functions#}.
7024 </p>
7025 {#header_close#}
7026
7027 {#header_open|@Frame#}
7028 <pre>{#syntax#}@Frame(func: var) type{#endsyntax#}</pre>
7029 <p>
7030 This function returns the frame type of a function. This works for {#link|Async Functions#}
7031 as well as any function without a specific calling convention.
7032 </p>
7033 <p>
7034 This type is suitable to be used as the return type of {#link|async|Async and Await#} which
7035 allows one to, for example, heap-allocate an async function frame:
7036 </p>
7037 {#code_begin|test#}
7038const std = @import("std");
7039
7040test "heap allocated frame" {
7041 const frame = try std.heap.direct_allocator.create(@Frame(func));
7042 frame.* = async func();
7043}
7044
7045fn func() void {
7046 suspend;
7047}
7048 {#code_end#}
7049 {#header_close#}
7050
68867051 {#header_open|@frameAddress#}
68877052 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
68887053 <p>
......@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}
68987063 </p>
68997064 {#header_close#}
69007065
6901 {#header_open|@handle#}
6902 <pre>{#syntax#}@handle(){#endsyntax#}</pre>
7066 {#header_open|@frameSize#}
7067 <pre>{#syntax#}@frameSize() usize{#endsyntax#}</pre>
69037068 <p>
6904 This function returns a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
6905 is the return type of the async function in scope.
7069 This is the same as {#syntax#}@sizeOf(@Frame(func)){#endsyntax#}, where {#syntax#}func{#endsyntax#}
7070 may be runtime-known.
69067071 </p>
69077072 <p>
6908 This function is only valid within an async function scope.
7073 This function is typically used in conjunction with {#link|@asyncCall#}.
69097074 </p>
69107075 {#header_close#}
69117076
......@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {
80458210 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
80468211 <ul>
80478212 <li>All {#link|Thread Local Variables#} are treated as {#link|Global Variables#}.</li>
8048 <li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.
8049 TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
8213 <li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
80508214 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
80518215 and therefore various userland APIs which read this variable become more efficient.
80528216 For example {#syntax#}std.Mutex{#endsyntax#} becomes
......@@ -9794,7 +9958,6 @@ PrimaryExpr
97949958 &lt;- AsmExpr
97959959 / IfExpr
97969960 / KEYWORD_break BreakLabel? Expr?
9797 / KEYWORD_cancel Expr
97989961 / KEYWORD_comptime Expr
97999962 / KEYWORD_continue BreakLabel?
98009963 / KEYWORD_resume Expr
......@@ -9825,7 +9988,7 @@ TypeExpr &lt;- PrefixTypeOp* ErrorUnionExpr
98259988ErrorUnionExpr &lt;- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
98269989
98279990SuffixExpr
9828 &lt;- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
9991 &lt;- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
98299992 / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
98309993
98319994PrimaryTypeExpr
......@@ -9901,7 +10064,7 @@ FnCC
990110064 &lt;- KEYWORD_nakedcc
990210065 / KEYWORD_stdcallcc
990310066 / KEYWORD_extern
9904 / KEYWORD_async (LARROW TypeExpr RARROW)?
10067 / KEYWORD_async
990510068
990610069ParamDecl &lt;- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
990710070
......@@ -10006,8 +10169,6 @@ SuffixOp
1000610169 / DOTASTERISK
1000710170 / DOTQUESTIONMARK
1000810171
10009AsyncPrefix &lt;- KEYWORD_async (LARROW PrefixExpr RARROW)?
10010
1001110172FnCallArguments &lt;- LPAREN ExprList RPAREN
1001210173
1001310174# Ptr specific
......@@ -10150,7 +10311,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word
1015010311KEYWORD_async &lt;- 'async' end_of_word
1015110312KEYWORD_await &lt;- 'await' end_of_word
1015210313KEYWORD_break &lt;- 'break' end_of_word
10153KEYWORD_cancel &lt;- 'cancel' end_of_word
1015410314KEYWORD_catch &lt;- 'catch' end_of_word
1015510315KEYWORD_comptime &lt;- 'comptime' end_of_word
1015610316KEYWORD_const &lt;- 'const' end_of_word
......@@ -10195,7 +10355,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word
1019510355KEYWORD_while &lt;- 'while' end_of_word
1019610356
1019710357keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm
10198 / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel
10358 / KEYWORD_async / KEYWORD_await / KEYWORD_break
1019910359 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
1020010360 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
1020110361 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
src-self-hosted/ir.zig-15
......@@ -1181,7 +1181,6 @@ pub const Builder = struct {
11811181 ast.Node.Id.ErrorTag => return error.Unimplemented,
11821182 ast.Node.Id.AsmInput => return error.Unimplemented,
11831183 ast.Node.Id.AsmOutput => return error.Unimplemented,
1184 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
11851184 ast.Node.Id.ParamDecl => return error.Unimplemented,
11861185 ast.Node.Id.FieldInitializer => return error.Unimplemented,
11871186 ast.Node.Id.EnumLiteral => return error.Unimplemented,
......@@ -1904,20 +1903,6 @@ pub const Builder = struct {
19041903 }
19051904 return error.Unimplemented;
19061905
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
19211906 }
19221907
19231908 const Ident = union(enum) {
src-self-hosted/link.zig+1-1
......@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
627627
628628fn addFnObjects(ctx: *Context) !void {
629629 // at this point it's guaranteed nobody else has this lock, so we circumvent it
630 // and avoid having to be a coroutine
630 // and avoid having to be an async function
631631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
632632
633633 var it = fn_link_set.first;
src-self-hosted/main.zig+9-12
......@@ -52,7 +52,7 @@ const Command = struct {
5252
5353pub fn main() !void {
5454 // This allocator needs to be thread-safe because we use it for the event.Loop
55 // which multiplexes coroutines onto kernel threads.
55 // which multiplexes async functions onto kernel threads.
5656 // libc allocator is guaranteed to have this property.
5757 const allocator = std.heap.c_allocator;
5858
......@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
466466 comp.link_objects = link_objects;
467467
468468 comp.start();
469 const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
470 defer cancel process_build_events_handle;
469 // TODO const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
471470 loop.run();
472471}
473472
......@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
578577 var zig_compiler = try ZigCompiler.init(&loop);
579578 defer zig_compiler.deinit();
580579
581 const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
582 defer cancel handle;
580 // TODO const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
583581
584582 loop.run();
585583}
......@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
663661 defer loop.deinit();
664662
665663 var result: FmtError!void = undefined;
666 const main_handle = try async<allocator> asyncFmtMainChecked(
667 &result,
668 &loop,
669 &flags,
670 color,
671 );
672 defer cancel main_handle;
664 // TODO const main_handle = try async<allocator> asyncFmtMainChecked(
665 // TODO &result,
666 // TODO &loop,
667 // TODO &flags,
668 // TODO color,
669 // TODO );
673670 loop.run();
674671 return result;
675672}
src-self-hosted/stage1.zig+2-1
......@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
142142 return Error.None;
143143}
144144
145// TODO: just use the actual self-hosted zig fmt. Until the coroutine rewrite, we use a blocking implementation.
145// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
146// we use a blocking implementation.
146147export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
147148 if (std.debug.runtime_safety) {
148149 fmtMain(argc, argv) catch unreachable;
src-self-hosted/translate_c.zig+1-2
......@@ -1037,7 +1037,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
10371037 .op = ast.Node.SuffixOp.Op{
10381038 .Call = ast.Node.SuffixOp.Op.Call{
10391039 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
1040 .async_attr = null,
1040 .async_token = null,
10411041 },
10421042 },
10431043 .rtoken = undefined, // set after appending args
......@@ -1355,7 +1355,6 @@ fn finishTransFnProto(
13551355 .var_args_token = null, // TODO this field is broken in the AST data model
13561356 .extern_export_inline_token = extern_export_inline_tok,
13571357 .cc_token = cc_tok,
1358 .async_attr = null,
13591358 .body_node = null,
13601359 .lib_name = null,
13611360 .align_expr = null,
src/all_types.hpp+162-217
......@@ -35,6 +35,7 @@ struct ConstExprValue;
3535struct IrInstruction;
3636struct IrInstructionCast;
3737struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;
3839struct IrBasicBlock;
3940struct ScopeDecls;
4041struct ZigWindowsSDK;
......@@ -70,20 +71,10 @@ struct IrExecutable {
7071 Scope *begin_scope;
7172 ZigList<Tld *> tld_list;
7273
73 IrInstruction *coro_handle;
74 IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
75 IrInstruction *coro_result_ptr_field_ptr;
76 IrInstruction *coro_result_field_ptr;
77 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
78 IrBasicBlock *coro_early_final;
79 IrBasicBlock *coro_normal_final;
80 IrBasicBlock *coro_suspend_block;
81 IrBasicBlock *coro_final_cleanup_block;
82 ZigVar *coro_allocator_var;
83
8474 bool invalid;
8575 bool is_inline;
8676 bool is_generic_instantiation;
77 bool need_err_code_spill;
8778};
8879
8980enum OutType {
......@@ -485,11 +476,10 @@ enum NodeType {
485476 NodeTypeIfErrorExpr,
486477 NodeTypeIfOptional,
487478 NodeTypeErrorSetDecl,
488 NodeTypeCancel,
489479 NodeTypeResume,
490480 NodeTypeAwaitExpr,
491481 NodeTypeSuspend,
492 NodeTypePromiseType,
482 NodeTypeAnyFrameType,
493483 NodeTypeEnumLiteral,
494484};
495485
......@@ -522,7 +512,6 @@ struct AstNodeFnProto {
522512 AstNode *section_expr;
523513
524514 bool auto_err_set;
525 AstNode *async_allocator_type;
526515};
527516
528517struct AstNodeFnDef {
......@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {
657646 bool is_builtin;
658647 bool is_async;
659648 bool seen; // used by @compileLog
660 AstNode *async_allocator;
661649};
662650
663651struct AstNodeArrayAccessExpr {
......@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {
922910 AstNode *expr; // may be null
923911};
924912
925struct AstNodeCancelExpr {
926 AstNode *expr;
927};
928
929913struct AstNodeResumeExpr {
930914 AstNode *expr;
931915};
......@@ -949,7 +933,7 @@ struct AstNodeSuspend {
949933 AstNode *block;
950934};
951935
952struct AstNodePromiseType {
936struct AstNodeAnyFrameType {
953937 AstNode *payload_type; // can be NULL
954938};
955939
......@@ -1014,13 +998,16 @@ struct AstNode {
1014998 AstNodeInferredArrayType inferred_array_type;
1015999 AstNodeErrorType error_type;
10161000 AstNodeErrorSetDecl err_set_decl;
1017 AstNodeCancelExpr cancel_expr;
10181001 AstNodeResumeExpr resume_expr;
10191002 AstNodeAwaitExpr await_expr;
10201003 AstNodeSuspend suspend;
1021 AstNodePromiseType promise_type;
1004 AstNodeAnyFrameType anyframe_type;
10221005 AstNodeEnumLiteral enum_literal;
10231006 } data;
1007
1008 // This is a function for use in the debugger to print
1009 // the source location.
1010 void src();
10241011};
10251012
10261013// this struct is allocated with allocate_nonzero
......@@ -1047,7 +1034,6 @@ struct FnTypeId {
10471034 bool is_var_args;
10481035 CallingConvention cc;
10491036 uint32_t alignment;
1050 ZigType *async_allocator_type;
10511037};
10521038
10531039uint32_t fn_type_id_hash(FnTypeId*);
......@@ -1095,6 +1081,7 @@ struct TypeStructField {
10951081 ConstExprValue *init_val; // null and then memoized
10961082 uint32_t bit_offset_in_host; // offset from the memory at gen_index
10971083 uint32_t host_int_bytes; // size of host integer
1084 uint32_t align;
10981085};
10991086
11001087enum ResolveStatus {
......@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {
11561143struct ZigTypeErrorUnion {
11571144 ZigType *err_set_type;
11581145 ZigType *payload_type;
1146 size_t pad_bytes;
1147 LLVMTypeRef pad_llvm_type;
11591148};
11601149
11611150struct ZigTypeErrorSet {
......@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {
12411230 ZigType *fn_type;
12421231};
12431232
1244struct ZigTypePromise {
1245 // null if `promise` instead of `promise->T`
1246 ZigType *result_type;
1247};
1248
12491233struct ZigTypeVector {
12501234 // The type must be a pointer, integer, or float
12511235 ZigType *elem_type;
......@@ -1276,7 +1260,8 @@ enum ZigTypeId {
12761260 ZigTypeIdBoundFn,
12771261 ZigTypeIdArgTuple,
12781262 ZigTypeIdOpaque,
1279 ZigTypeIdPromise,
1263 ZigTypeIdFnFrame,
1264 ZigTypeIdAnyFrame,
12801265 ZigTypeIdVector,
12811266 ZigTypeIdEnumLiteral,
12821267};
......@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {
12911276 Buf *bare_name;
12921277};
12931278
1279struct ZigTypeFnFrame {
1280 ZigFn *fn;
1281 ZigType *locals_struct;
1282};
1283
1284struct ZigTypeAnyFrame {
1285 ZigType *result_type; // null if `anyframe` instead of `anyframe->T`
1286};
1287
12941288struct ZigType {
12951289 ZigTypeId id;
12961290 Buf name;
......@@ -1314,16 +1308,16 @@ struct ZigType {
13141308 ZigTypeUnion unionation;
13151309 ZigTypeFn fn;
13161310 ZigTypeBoundFn bound_fn;
1317 ZigTypePromise promise;
13181311 ZigTypeVector vector;
13191312 ZigTypeOpaque opaque;
1313 ZigTypeFnFrame frame;
1314 ZigTypeAnyFrame any_frame;
13201315 } data;
13211316
13221317 // use these fields to make sure we don't duplicate type table entries for the same type
13231318 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]
13241319 ZigType *optional_parent;
1325 ZigType *promise_parent;
1326 ZigType *promise_frame_parent;
1320 ZigType *any_frame_parent;
13271321 // If we generate a constant name value for this type, we memoize it here.
13281322 // The type of this is array
13291323 ConstExprValue *cached_const_name_val;
......@@ -1359,7 +1353,6 @@ struct GlobalExport {
13591353};
13601354
13611355struct ZigFn {
1362 CodeGen *codegen;
13631356 LLVMValueRef llvm_value;
13641357 const char *llvm_name;
13651358 AstNode *proto_node;
......@@ -1368,7 +1361,17 @@ struct ZigFn {
13681361 Scope *child_scope; // parent is scope for last parameter
13691362 ScopeBlock *def_scope; // parent is child_scope
13701363 Buf symbol_name;
1371 ZigType *type_entry; // function type
1364 // This is the function type assuming the function does not suspend.
1365 // Note that for an async function, this can be shared with non-async functions. So the value here
1366 // should only be read for things in common between non-async and async function types.
1367 ZigType *type_entry;
1368 // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type.
1369 // However for functions that suspend, those values could possibly be their non-suspending equivalents.
1370 // So these values should be preferred.
1371 LLVMTypeRef raw_type_ref;
1372 ZigLLVMDIType *raw_di_type;
1373
1374 ZigType *frame_type;
13721375 // in the case of normal functions this is the implicit return type
13731376 // in the case of async functions this is the implicit return type according to the
13741377 // zig source code, not according to zig ir
......@@ -1379,6 +1382,7 @@ struct ZigFn {
13791382 size_t prealloc_backward_branch_quota;
13801383 AstNode **param_source_nodes;
13811384 Buf **param_names;
1385 IrInstruction *err_code_spill;
13821386
13831387 AstNode *fn_no_inline_set_node;
13841388 AstNode *fn_static_eval_set_node;
......@@ -1390,8 +1394,11 @@ struct ZigFn {
13901394 AstNode *set_alignstack_node;
13911395
13921396 AstNode *set_cold_node;
1397 const AstNode *inferred_async_node;
1398 ZigFn *inferred_async_fn;
13931399
13941400 ZigList<GlobalExport> export_list;
1401 ZigList<IrInstructionCallGen *> call_list;
13951402
13961403 LLVMValueRef valgrind_client_request_array;
13971404
......@@ -1442,8 +1449,6 @@ enum BuiltinFnId {
14421449 BuiltinFnIdErrName,
14431450 BuiltinFnIdBreakpoint,
14441451 BuiltinFnIdReturnAddress,
1445 BuiltinFnIdFrameAddress,
1446 BuiltinFnIdHandle,
14471452 BuiltinFnIdEmbedFile,
14481453 BuiltinFnIdCmpxchgWeak,
14491454 BuiltinFnIdCmpxchgStrong,
......@@ -1499,6 +1504,7 @@ enum BuiltinFnId {
14991504 BuiltinFnIdInlineCall,
15001505 BuiltinFnIdNoInlineCall,
15011506 BuiltinFnIdNewStackCall,
1507 BuiltinFnIdAsyncCall,
15021508 BuiltinFnIdTypeId,
15031509 BuiltinFnIdShlExact,
15041510 BuiltinFnIdShrExact,
......@@ -1514,6 +1520,10 @@ enum BuiltinFnId {
15141520 BuiltinFnIdAtomicLoad,
15151521 BuiltinFnIdHasDecl,
15161522 BuiltinFnIdUnionInit,
1523 BuiltinFnIdFrameAddress,
1524 BuiltinFnIdFrameType,
1525 BuiltinFnIdFrameHandle,
1526 BuiltinFnIdFrameSize,
15171527};
15181528
15191529struct BuiltinFnEntry {
......@@ -1541,6 +1551,12 @@ enum PanicMsgId {
15411551 PanicMsgIdBadEnumValue,
15421552 PanicMsgIdFloatToInt,
15431553 PanicMsgIdPtrCastNull,
1554 PanicMsgIdBadResume,
1555 PanicMsgIdBadAwait,
1556 PanicMsgIdBadReturn,
1557 PanicMsgIdResumedAnAwaitingFn,
1558 PanicMsgIdFrameTooSmall,
1559 PanicMsgIdResumedFnPendingAwait,
15441560
15451561 PanicMsgIdCount,
15461562};
......@@ -1701,7 +1717,13 @@ struct CodeGen {
17011717 LLVMTargetMachineRef target_machine;
17021718 ZigLLVMDIFile *dummy_di_file;
17031719 LLVMValueRef cur_ret_ptr;
1720 LLVMValueRef cur_frame_ptr;
17041721 LLVMValueRef cur_fn_val;
1722 LLVMValueRef cur_async_switch_instr;
1723 LLVMValueRef cur_async_resume_index_ptr;
1724 LLVMValueRef cur_async_awaiter_ptr;
1725 LLVMBasicBlockRef cur_preamble_llvm_block;
1726 size_t cur_resume_block_count;
17051727 LLVMValueRef cur_err_ret_trace_val_arg;
17061728 LLVMValueRef cur_err_ret_trace_val_stack;
17071729 LLVMValueRef memcpy_fn_val;
......@@ -1709,28 +1731,16 @@ struct CodeGen {
17091731 LLVMValueRef trap_fn_val;
17101732 LLVMValueRef return_address_fn_val;
17111733 LLVMValueRef frame_address_fn_val;
1712 LLVMValueRef coro_destroy_fn_val;
1713 LLVMValueRef coro_id_fn_val;
1714 LLVMValueRef coro_alloc_fn_val;
1715 LLVMValueRef coro_size_fn_val;
1716 LLVMValueRef coro_begin_fn_val;
1717 LLVMValueRef coro_suspend_fn_val;
1718 LLVMValueRef coro_end_fn_val;
1719 LLVMValueRef coro_free_fn_val;
1720 LLVMValueRef coro_resume_fn_val;
1721 LLVMValueRef coro_save_fn_val;
1722 LLVMValueRef coro_promise_fn_val;
1723 LLVMValueRef coro_alloc_helper_fn_val;
1724 LLVMValueRef coro_frame_fn_val;
1725 LLVMValueRef merge_err_ret_traces_fn_val;
17261734 LLVMValueRef add_error_return_trace_addr_fn_val;
17271735 LLVMValueRef stacksave_fn_val;
17281736 LLVMValueRef stackrestore_fn_val;
17291737 LLVMValueRef write_register_fn_val;
1738 LLVMValueRef merge_err_ret_traces_fn_val;
17301739 LLVMValueRef sp_md_node;
17311740 LLVMValueRef err_name_table;
17321741 LLVMValueRef safety_crash_err_fn;
17331742 LLVMValueRef return_err_fn;
1743 LLVMTypeRef anyframe_fn_type;
17341744
17351745 // reminder: hash tables must be initialized before use
17361746 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
......@@ -1797,12 +1807,12 @@ struct CodeGen {
17971807 ZigType *entry_var;
17981808 ZigType *entry_global_error_set;
17991809 ZigType *entry_arg_tuple;
1800 ZigType *entry_promise;
18011810 ZigType *entry_enum_literal;
1811 ZigType *entry_any_frame;
18021812 } builtin_types;
1813
18031814 ZigType *align_amt_type;
18041815 ZigType *stack_trace_type;
1805 ZigType *ptr_to_stack_trace_type;
18061816 ZigType *err_tag_type;
18071817 ZigType *test_fn_type;
18081818
......@@ -1938,6 +1948,7 @@ struct ZigVar {
19381948 ZigType *var_type;
19391949 LLVMValueRef value_ref;
19401950 IrInstruction *is_comptime;
1951 IrInstruction *ptr_instruction;
19411952 // which node is the declaration of the variable
19421953 AstNode *decl_node;
19431954 ZigLLVMDILocalVariable *di_loc_var;
......@@ -1985,7 +1996,6 @@ enum ScopeId {
19851996 ScopeIdSuspend,
19861997 ScopeIdFnDef,
19871998 ScopeIdCompTime,
1988 ScopeIdCoroPrelude,
19891999 ScopeIdRuntime,
19902000};
19912001
......@@ -2109,7 +2119,6 @@ struct ScopeRuntime {
21092119struct ScopeSuspend {
21102120 Scope base;
21112121
2112 IrBasicBlock *resume_block;
21132122 bool reported_err;
21142123};
21152124
......@@ -2128,12 +2137,6 @@ struct ScopeFnDef {
21282137 ZigFn *fn_entry;
21292138};
21302139
2131// This scope is created to indicate that the code in the scope
2132// is auto-generated coroutine prelude stuff.
2133struct ScopeCoroPrelude {
2134 Scope base;
2135};
2136
21372140// synchronized with code in define_builtin_compile_vars
21382141enum AtomicOrder {
21392142 AtomicOrderUnordered,
......@@ -2231,7 +2234,7 @@ enum IrInstructionId {
22312234 IrInstructionIdSetRuntimeSafety,
22322235 IrInstructionIdSetFloatMode,
22332236 IrInstructionIdArrayType,
2234 IrInstructionIdPromiseType,
2237 IrInstructionIdAnyFrameType,
22352238 IrInstructionIdSliceType,
22362239 IrInstructionIdGlobalAsm,
22372240 IrInstructionIdAsm,
......@@ -2278,7 +2281,10 @@ enum IrInstructionId {
22782281 IrInstructionIdBreakpoint,
22792282 IrInstructionIdReturnAddress,
22802283 IrInstructionIdFrameAddress,
2281 IrInstructionIdHandle,
2284 IrInstructionIdFrameHandle,
2285 IrInstructionIdFrameType,
2286 IrInstructionIdFrameSizeSrc,
2287 IrInstructionIdFrameSizeGen,
22822288 IrInstructionIdAlignOf,
22832289 IrInstructionIdOverflowOp,
22842290 IrInstructionIdTestErrSrc,
......@@ -2321,35 +2327,16 @@ enum IrInstructionId {
23212327 IrInstructionIdImplicitCast,
23222328 IrInstructionIdResolveResult,
23232329 IrInstructionIdResetResult,
2324 IrInstructionIdResultPtr,
23252330 IrInstructionIdOpaqueType,
23262331 IrInstructionIdSetAlignStack,
23272332 IrInstructionIdArgType,
23282333 IrInstructionIdExport,
23292334 IrInstructionIdErrorReturnTrace,
23302335 IrInstructionIdErrorUnion,
2331 IrInstructionIdCancel,
2332 IrInstructionIdGetImplicitAllocator,
2333 IrInstructionIdCoroId,
2334 IrInstructionIdCoroAlloc,
2335 IrInstructionIdCoroSize,
2336 IrInstructionIdCoroBegin,
2337 IrInstructionIdCoroAllocFail,
2338 IrInstructionIdCoroSuspend,
2339 IrInstructionIdCoroEnd,
2340 IrInstructionIdCoroFree,
2341 IrInstructionIdCoroResume,
2342 IrInstructionIdCoroSave,
2343 IrInstructionIdCoroPromise,
2344 IrInstructionIdCoroAllocHelper,
23452336 IrInstructionIdAtomicRmw,
23462337 IrInstructionIdAtomicLoad,
2347 IrInstructionIdPromiseResultType,
2348 IrInstructionIdAwaitBookkeeping,
23492338 IrInstructionIdSaveErrRetAddr,
23502339 IrInstructionIdAddImplicitReturnType,
2351 IrInstructionIdMergeErrRetTraces,
2352 IrInstructionIdMarkErrRetTracePtr,
23532340 IrInstructionIdErrSetCast,
23542341 IrInstructionIdToBytes,
23552342 IrInstructionIdFromBytes,
......@@ -2365,6 +2352,13 @@ enum IrInstructionId {
23652352 IrInstructionIdEndExpr,
23662353 IrInstructionIdPtrOfArrayToSlice,
23672354 IrInstructionIdUnionInitNamedField,
2355 IrInstructionIdSuspendBegin,
2356 IrInstructionIdSuspendFinish,
2357 IrInstructionIdAwaitSrc,
2358 IrInstructionIdAwaitGen,
2359 IrInstructionIdResume,
2360 IrInstructionIdSpillBegin,
2361 IrInstructionIdSpillEnd,
23682362};
23692363
23702364struct IrInstruction {
......@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {
26072601 IrInstruction **args;
26082602 ResultLoc *result_loc;
26092603
2610 IrInstruction *async_allocator;
26112604 IrInstruction *new_stack;
26122605 FnInline fn_inline;
26132606 bool is_async;
......@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {
26222615 size_t arg_count;
26232616 IrInstruction **args;
26242617 IrInstruction *result_loc;
2618 IrInstruction *frame_result_loc;
26252619
2626 IrInstruction *async_allocator;
26272620 IrInstruction *new_stack;
26282621 FnInline fn_inline;
26292622 bool is_async;
......@@ -2639,7 +2632,7 @@ struct IrInstructionConst {
26392632struct IrInstructionReturn {
26402633 IrInstruction base;
26412634
2642 IrInstruction *value;
2635 IrInstruction *operand;
26432636};
26442637
26452638enum CastOp {
......@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {
27442737 bool is_allow_zero;
27452738};
27462739
2747struct IrInstructionPromiseType {
2740struct IrInstructionAnyFrameType {
27482741 IrInstruction base;
27492742
27502743 IrInstruction *payload_type;
......@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {
30843077 IrInstruction base;
30853078};
30863079
3087struct IrInstructionHandle {
3080struct IrInstructionFrameHandle {
3081 IrInstruction base;
3082};
3083
3084struct IrInstructionFrameType {
3085 IrInstruction base;
3086
3087 IrInstruction *fn;
3088};
3089
3090struct IrInstructionFrameSizeSrc {
3091 IrInstruction base;
3092
3093 IrInstruction *fn;
3094};
3095
3096struct IrInstructionFrameSizeGen {
30883097 IrInstruction base;
3098
3099 IrInstruction *fn;
30893100};
30903101
30913102enum IrOverflowOp {
......@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {
31273138 IrInstruction base;
31283139
31293140 bool resolve_err_set;
3141 bool base_ptr_is_payload;
31303142 IrInstruction *base_ptr;
31313143};
31323144
......@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {
31793191 IrInstruction **param_types;
31803192 IrInstruction *align_value;
31813193 IrInstruction *return_type;
3182 IrInstruction *async_allocator_type_value;
31833194 bool is_var_args;
31843195};
31853196
......@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {
34093420 IrInstruction *payload;
34103421};
34113422
3412struct IrInstructionCancel {
3413 IrInstruction base;
3414
3415 IrInstruction *target;
3416};
3417
3418enum ImplicitAllocatorId {
3419 ImplicitAllocatorIdArg,
3420 ImplicitAllocatorIdLocalVar,
3421};
3422
3423struct IrInstructionGetImplicitAllocator {
3424 IrInstruction base;
3425
3426 ImplicitAllocatorId id;
3427};
3428
3429struct IrInstructionCoroId {
3430 IrInstruction base;
3431
3432 IrInstruction *promise_ptr;
3433};
3434
3435struct IrInstructionCoroAlloc {
3436 IrInstruction base;
3437
3438 IrInstruction *coro_id;
3439};
3440
3441struct IrInstructionCoroSize {
3442 IrInstruction base;
3443};
3444
3445struct IrInstructionCoroBegin {
3446 IrInstruction base;
3447
3448 IrInstruction *coro_id;
3449 IrInstruction *coro_mem_ptr;
3450};
3451
3452struct IrInstructionCoroAllocFail {
3453 IrInstruction base;
3454
3455 IrInstruction *err_val;
3456};
3457
3458struct IrInstructionCoroSuspend {
3459 IrInstruction base;
3460
3461 IrInstruction *save_point;
3462 IrInstruction *is_final;
3463};
3464
3465struct IrInstructionCoroEnd {
3466 IrInstruction base;
3467};
3468
3469struct IrInstructionCoroFree {
3470 IrInstruction base;
3471
3472 IrInstruction *coro_id;
3473 IrInstruction *coro_handle;
3474};
3475
3476struct IrInstructionCoroResume {
3477 IrInstruction base;
3478
3479 IrInstruction *awaiter_handle;
3480};
3481
3482struct IrInstructionCoroSave {
3483 IrInstruction base;
3484
3485 IrInstruction *coro_handle;
3486};
3487
3488struct IrInstructionCoroPromise {
3489 IrInstruction base;
3490
3491 IrInstruction *coro_handle;
3492};
3493
3494struct IrInstructionCoroAllocHelper {
3495 IrInstruction base;
3496
3497 IrInstruction *realloc_fn;
3498 IrInstruction *coro_size;
3499};
3500
35013423struct IrInstructionAtomicRmw {
35023424 IrInstruction base;
35033425
......@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {
35193441 AtomicOrder resolved_ordering;
35203442};
35213443
3522struct IrInstructionPromiseResultType {
3523 IrInstruction base;
3524
3525 IrInstruction *promise_type;
3526};
3527
3528struct IrInstructionAwaitBookkeeping {
3529 IrInstruction base;
3530
3531 IrInstruction *promise_result_type;
3532};
3533
35343444struct IrInstructionSaveErrRetAddr {
35353445 IrInstruction base;
35363446};
......@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {
35413451 IrInstruction *value;
35423452};
35433453
3544struct IrInstructionMergeErrRetTraces {
3545 IrInstruction base;
3546
3547 IrInstruction *coro_promise_ptr;
3548 IrInstruction *src_err_ret_trace_ptr;
3549 IrInstruction *dest_err_ret_trace_ptr;
3550};
3551
3552struct IrInstructionMarkErrRetTracePtr {
3553 IrInstruction base;
3554
3555 IrInstruction *err_ret_trace_ptr;
3556};
3557
35583454// For float ops which take a single argument
35593455struct IrInstructionFloatOp {
35603456 IrInstruction base;
......@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {
36453541
36463542 uint32_t align;
36473543 const char *name_hint;
3544 size_t field_index;
36483545};
36493546
36503547struct IrInstructionEndExpr {
......@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {
36923589 IrInstruction *result_loc;
36933590};
36943591
3592struct IrInstructionSuspendBegin {
3593 IrInstruction base;
3594
3595 LLVMBasicBlockRef resume_bb;
3596};
3597
3598struct IrInstructionSuspendFinish {
3599 IrInstruction base;
3600
3601 IrInstructionSuspendBegin *begin;
3602};
3603
3604struct IrInstructionAwaitSrc {
3605 IrInstruction base;
3606
3607 IrInstruction *frame;
3608 ResultLoc *result_loc;
3609};
3610
3611struct IrInstructionAwaitGen {
3612 IrInstruction base;
3613
3614 IrInstruction *frame;
3615 IrInstruction *result_loc;
3616};
3617
3618struct IrInstructionResume {
3619 IrInstruction base;
3620
3621 IrInstruction *frame;
3622};
3623
3624enum SpillId {
3625 SpillIdInvalid,
3626 SpillIdRetErrCode,
3627};
3628
3629struct IrInstructionSpillBegin {
3630 IrInstruction base;
3631
3632 SpillId spill_id;
3633 IrInstruction *operand;
3634};
3635
3636struct IrInstructionSpillEnd {
3637 IrInstruction base;
3638
3639 IrInstructionSpillBegin *begin;
3640};
3641
36953642enum ResultLocId {
36963643 ResultLocIdInvalid,
36973644 ResultLocIdNone,
......@@ -3772,23 +3719,19 @@ static const size_t slice_len_index = 1;
37723719static const size_t maybe_child_index = 0;
37733720static const size_t maybe_null_index = 1;
37743721
3775static const size_t err_union_err_index = 0;
3776static const size_t err_union_payload_index = 1;
3722static const size_t err_union_payload_index = 0;
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 function
3779// MUST BE A POWER OF TWO.
3780static const size_t stack_trace_ptr_count = 32;
3725// label (grep this): [fn_frame_struct_layout]
3726static const size_t frame_fn_ptr_index = 0;
3727static const size_t frame_resume_index = 1;
3728static const size_t frame_awaiter_index = 2;
3729static const size_t frame_ret_start = 3;
37813730
3782// these belong to the async function
3783#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3784#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3785#define RESULT_FIELD_NAME "result"
3786#define ASYNC_REALLOC_FIELD_NAME "reallocFn"
3787#define ASYNC_SHRINK_FIELD_NAME "shrinkFn"
3788#define ATOMIC_STATE_FIELD_NAME "atomic_state"
3789// these point to data belonging to the awaiter
3790#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3791#define RESULT_PTR_FIELD_NAME "result_ptr"
3731// TODO https://github.com/ziglang/zig/issues/3056
3732// We require this to be a power of 2 so that we can use shifting rather than
3733// remainder division.
3734static const size_t stack_trace_ptr_count = 32; // Must be a power of 2.
37923735
37933736#define NAMESPACE_SEP_CHAR '.'
37943737#define NAMESPACE_SEP_STR "."
......@@ -3811,11 +3754,13 @@ enum FnWalkId {
38113754
38123755struct FnWalkAttrs {
38133756 ZigFn *fn;
3757 LLVMValueRef llvm_fn;
38143758 unsigned gen_i;
38153759};
38163760
38173761struct FnWalkCall {
38183762 ZigList<LLVMValueRef> *gen_param_values;
3763 ZigList<ZigType *> *gen_param_types;
38193764 IrInstructionCallGen *inst;
38203765 bool is_var_args;
38213766};
src/analyze.cpp+882-244
......@@ -7,6 +7,7 @@
77
88#include "analyze.hpp"
99#include "ast_render.hpp"
10#include "codegen.hpp"
1011#include "config.h"
1112#include "error.hpp"
1213#include "ir.hpp"
......@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
3132static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
3233static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
3334
35// nullptr means not analyzed yet; this one means currently being analyzed
36static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
37// this one means analyzed and it's not async
38static const AstNode *inferred_async_none = reinterpret_cast<AstNode *>(0x2);
39
3440static bool is_top_level_struct(ZigType *import) {
3541 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
3642}
......@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
5662 return err;
5763}
5864
59ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
65ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
6066 Token fake_token;
6167 fake_token.start_line = node->line;
6268 fake_token.start_column = node->column;
6369 return add_token_error(g, node->owner, &fake_token, msg);
6470}
6571
66ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
72ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) {
6773 Token fake_token;
6874 fake_token.start_line = node->line;
6975 fake_token.start_column = node->column;
......@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
188194 return &scope->base;
189195}
190196
191Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
192 ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1);
193 init_scope(g, &scope->base, ScopeIdCoroPrelude, node, parent);
194 return &scope->base;
195}
196
197197ZigType *get_scope_import(Scope *scope) {
198198 while (scope) {
199199 if (scope->id == ScopeIdDecls) {
......@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
234234 return type_entry->data.enumeration.decl_node;
235235 case ZigTypeIdUnion:
236236 return type_entry->data.unionation.decl_node;
237 case ZigTypeIdFnFrame:
238 return type_entry->data.frame.fn->proto_node;
237239 case ZigTypeIdOpaque:
238240 case ZigTypeIdMetaType:
239241 case ZigTypeIdVoid:
......@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
254256 case ZigTypeIdFn:
255257 case ZigTypeIdBoundFn:
256258 case ZigTypeIdArgTuple:
257 case ZigTypeIdPromise:
258259 case ZigTypeIdVector:
260 case ZigTypeIdAnyFrame:
259261 return nullptr;
260262 }
261263 zig_unreachable();
......@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
269271 return type_entry->data.structure.resolve_status >= status;
270272 case ZigTypeIdUnion:
271273 return type_entry->data.unionation.resolve_status >= status;
274 case ZigTypeIdFnFrame:
275 switch (status) {
276 case ResolveStatusInvalid:
277 zig_unreachable();
278 case ResolveStatusUnstarted:
279 case ResolveStatusZeroBitsKnown:
280 return true;
281 case ResolveStatusAlignmentKnown:
282 case ResolveStatusSizeKnown:
283 return type_entry->data.frame.locals_struct != nullptr;
284 case ResolveStatusLLVMFwdDecl:
285 case ResolveStatusLLVMFull:
286 return type_entry->llvm_type != nullptr;
287 }
272288 case ZigTypeIdEnum:
273289 switch (status) {
274290 case ResolveStatusUnstarted:
......@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
307323 case ZigTypeIdFn:
308324 case ZigTypeIdBoundFn:
309325 case ZigTypeIdArgTuple:
310 case ZigTypeIdPromise:
311326 case ZigTypeIdVector:
327 case ZigTypeIdAnyFrame:
312328 return true;
313329 }
314330 zig_unreachable();
......@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
341357 return get_int_type(g, false, bits_needed_for_unsigned(x));
342358}
343359
344ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
345 if (result_type != nullptr && result_type->promise_parent != nullptr) {
346 return result_type->promise_parent;
347 } else if (result_type == nullptr && g->builtin_types.entry_promise != nullptr) {
348 return g->builtin_types.entry_promise;
360ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) {
361 if (result_type != nullptr && result_type->any_frame_parent != nullptr) {
362 return result_type->any_frame_parent;
363 } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) {
364 return g->builtin_types.entry_any_frame;
349365 }
350366
351 ZigType *entry = new_type_table_entry(ZigTypeIdPromise);
367 ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame);
352368 entry->abi_size = g->builtin_types.entry_usize->abi_size;
353369 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
354370 entry->abi_align = g->builtin_types.entry_usize->abi_align;
355 entry->data.promise.result_type = result_type;
356 buf_init_from_str(&entry->name, "promise");
371 entry->data.any_frame.result_type = result_type;
372 buf_init_from_str(&entry->name, "anyframe");
357373 if (result_type != nullptr) {
358374 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
359375 }
360376
361377 if (result_type != nullptr) {
362 result_type->promise_parent = entry;
378 result_type->any_frame_parent = entry;
363379 } else if (result_type == nullptr) {
364 g->builtin_types.entry_promise = entry;
380 g->builtin_types.entry_any_frame = entry;
365381 }
366382 return entry;
367383}
......@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
378394 zig_unreachable();
379395}
380396
397ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
398 if (fn->frame_type != nullptr) {
399 return fn->frame_type;
400 }
401
402 ZigType *entry = new_type_table_entry(ZigTypeIdFnFrame);
403 buf_resize(&entry->name, 0);
404 buf_appendf(&entry->name, "@Frame(%s)", buf_ptr(&fn->symbol_name));
405
406 entry->data.frame.fn = fn;
407
408 // Async function frames are always non-zero bits because they always have a resume index.
409 entry->abi_size = SIZE_MAX;
410 entry->size_in_bits = SIZE_MAX;
411
412 fn->frame_type = entry;
413 return entry;
414}
415
381416ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
382417 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
383418 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
......@@ -490,42 +525,6 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
490525 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
491526}
492527
493ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
494 if (return_type->promise_frame_parent != nullptr) {
495 return return_type->promise_frame_parent;
496 }
497
498 ZigType *atomic_state_type = g->builtin_types.entry_usize;
499 ZigType *result_ptr_type = get_pointer_to_type(g, return_type, false);
500
501 ZigList<const char *> field_names = {};
502 field_names.append(ATOMIC_STATE_FIELD_NAME);
503 field_names.append(RESULT_FIELD_NAME);
504 field_names.append(RESULT_PTR_FIELD_NAME);
505 if (g->have_err_ret_tracing) {
506 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
507 field_names.append(ERR_RET_TRACE_FIELD_NAME);
508 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
509 }
510
511 ZigList<ZigType *> field_types = {};
512 field_types.append(atomic_state_type);
513 field_types.append(return_type);
514 field_types.append(result_ptr_type);
515 if (g->have_err_ret_tracing) {
516 field_types.append(get_ptr_to_stack_trace_type(g));
517 field_types.append(g->stack_trace_type);
518 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
519 }
520
521 assert(field_names.length == field_types.length);
522 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
523 ZigType *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
524
525 return_type->promise_frame_parent = entry;
526 return entry;
527}
528
529528ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
530529 if (child_type->optional_parent != nullptr) {
531530 return child_type->optional_parent;
......@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
631630 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);
632631 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);
633632 entry->size_in_bits = entry->abi_size * 8;
633 entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]);
634634 }
635635
636636 g->type_table.put(type_id, entry);
......@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
828828 zig_unreachable();
829829}
830830
831ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {
831ZigType *get_stack_trace_type(CodeGen *g) {
832832 if (g->stack_trace_type == nullptr) {
833833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
834834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);
835835
836836 g->stack_trace_type = stack_trace_type_val->data.x_type;
837837 assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));
838
839 g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false);
840838 }
841 return g->ptr_to_stack_trace_type;
839 return g->stack_trace_type;
842840}
843841
844842bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
......@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
879877
880878 // populate the name of the type
881879 buf_resize(&fn_type->name, 0);
882 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
883 assert(fn_type_id->async_allocator_type != nullptr);
884 buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name));
885 } else {
886 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
887 buf_appendf(&fn_type->name, "%s", cc_str);
888 }
880 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
881 buf_appendf(&fn_type->name, "%s", cc_str);
889882 buf_appendf(&fn_type->name, "fn(");
890883 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
891884 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
......@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
998991ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
999992 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);
1000993 buf_resize(&fn_type->name, 0);
1001 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
1002 const char *async_allocator_type_str = (fn_type->data.fn.fn_type_id.async_allocator_type == nullptr) ?
1003 "var" : buf_ptr(&fn_type_id->async_allocator_type->name);
1004 buf_appendf(&fn_type->name, "async(%s) ", async_allocator_type_str);
1005 } else {
1006 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1007 buf_appendf(&fn_type->name, "%s", cc_str);
1008 }
994 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
995 buf_appendf(&fn_type->name, "%s", cc_str);
1009996 buf_appendf(&fn_type->name, "fn(");
1010997 size_t i = 0;
1011998 for (; i < fn_type_id->next_param_index; i += 1) {
......@@ -1119,7 +1106,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
11191106 case ZigTypeIdBoundFn:
11201107 case ZigTypeIdArgTuple:
11211108 case ZigTypeIdOpaque:
1122 case ZigTypeIdPromise:
1109 case ZigTypeIdFnFrame:
1110 case ZigTypeIdAnyFrame:
11231111 add_node_error(g, source_node,
11241112 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
11251113 buf_ptr(&type_entry->name)));
......@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
12071195 case ZigTypeIdErrorSet:
12081196 case ZigTypeIdBoundFn:
12091197 case ZigTypeIdArgTuple:
1210 case ZigTypeIdPromise:
12111198 case ZigTypeIdVoid:
1199 case ZigTypeIdFnFrame:
1200 case ZigTypeIdAnyFrame:
12121201 return false;
12131202 case ZigTypeIdOpaque:
12141203 case ZigTypeIdUnreachable:
......@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
13781367 case ZigTypeIdEnum:
13791368 case ZigTypeIdUnion:
13801369 case ZigTypeIdFn:
1381 case ZigTypeIdPromise:
13821370 case ZigTypeIdVector:
1371 case ZigTypeIdFnFrame:
1372 case ZigTypeIdAnyFrame:
13831373 switch (type_requires_comptime(g, type_entry)) {
13841374 case ReqCompTimeNo:
13851375 break;
......@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
14741464 case ZigTypeIdEnum:
14751465 case ZigTypeIdUnion:
14761466 case ZigTypeIdFn:
1477 case ZigTypeIdPromise:
14781467 case ZigTypeIdVector:
1468 case ZigTypeIdFnFrame:
1469 case ZigTypeIdAnyFrame:
14791470 switch (type_requires_comptime(g, fn_type_id.return_type)) {
14801471 case ReqCompTimeInvalid:
14811472 return g->builtin_types.entry_invalid;
......@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
14871478 break;
14881479 }
14891480
1490 if (fn_type_id.cc == CallingConventionAsync) {
1491 if (fn_proto->async_allocator_type == nullptr) {
1492 return get_generic_fn_type(g, &fn_type_id);
1493 }
1494 fn_type_id.async_allocator_type = analyze_type_expr(g, child_scope, fn_proto->async_allocator_type);
1495 if (type_is_invalid(fn_type_id.async_allocator_type)) {
1496 return g->builtin_types.entry_invalid;
1497 }
1498 }
1499
15001481 return get_fn_type(g, &fn_type_id);
15011482}
15021483
......@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {
15161497 zig_unreachable();
15171498}
15181499
1500struct SrcField {
1501 const char *name;
1502 ZigType *ty;
1503 unsigned align;
1504};
15191505
1520ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
1521 ZigType *field_types[], size_t field_count)
1506static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count,
1507 unsigned min_abi_align)
15221508{
15231509 ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
15241510
......@@ -1530,22 +1516,20 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15301516 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
15311517 struct_type->data.structure.fields_by_name.init(field_count);
15321518
1533 size_t abi_align = 0;
1519 size_t abi_align = min_abi_align;
15341520 for (size_t i = 0; i < field_count; i += 1) {
15351521 TypeStructField *field = &struct_type->data.structure.fields[i];
1536 field->name = buf_create_from_str(field_names[i]);
1537 field->type_entry = field_types[i];
1522 field->name = buf_create_from_str(fields[i].name);
1523 field->type_entry = fields[i].ty;
15381524 field->src_index = i;
1525 field->align = fields[i].align;
15391526
15401527 if (type_has_bits(field->type_entry)) {
15411528 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));
1542 if (field->type_entry->abi_align > abi_align) {
1543 abi_align = field->type_entry->abi_align;
1529 unsigned field_abi_align = max(field->align, field->type_entry->abi_align);
1530 if (field_abi_align > abi_align) {
1531 abi_align = field_abi_align;
15441532 }
1545 field->gen_index = struct_type->data.structure.gen_field_count;
1546 struct_type->data.structure.gen_field_count += 1;
1547 } else {
1548 field->gen_index = SIZE_MAX;
15491533 }
15501534
15511535 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
......@@ -1555,17 +1539,24 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
15551539 size_t next_offset = 0;
15561540 for (size_t i = 0; i < field_count; i += 1) {
15571541 TypeStructField *field = &struct_type->data.structure.fields[i];
1558 if (field->gen_index == SIZE_MAX)
1542 if (!type_has_bits(field->type_entry))
15591543 continue;
1544
15601545 field->offset = next_offset;
1546
1547 // find the next non-zero-byte field for offset calculations
15611548 size_t next_src_field_index = i + 1;
15621549 for (; next_src_field_index < field_count; next_src_field_index += 1) {
1563 if (struct_type->data.structure.fields[next_src_field_index].gen_index != SIZE_MAX) {
1550 if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
15641551 break;
1565 }
15661552 }
1567 size_t next_abi_align = (next_src_field_index == field_count) ?
1568 abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
1553 size_t next_abi_align;
1554 if (next_src_field_index == field_count) {
1555 next_abi_align = abi_align;
1556 } else {
1557 next_abi_align = max(fields[next_src_field_index].align,
1558 struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align);
1559 }
15691560 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);
15701561 }
15711562
......@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26532644
26542645 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26552646
2656 fn_entry->codegen = g;
26572647 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
26582648 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
26592649 fn_entry->analyzed_executable.fn_entry = fn_entry;
......@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
27812771 }
27822772 }
27832773 } else {
2774 fn_table_entry->inferred_async_node = inferred_async_none;
27842775 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
27852776 }
27862777
......@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
28022793 g->fn_defs.append(fn_table_entry);
28032794 }
28042795
2796 // if the calling convention implies that it cannot be async, we save that for later
2797 // and leave the value to be nullptr to indicate that we have not emitted possible
2798 // compile errors for improperly calling async functions.
2799 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
2800 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
2801 }
2802
28052803 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
28062804 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
28072805 {
......@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
30353033 case NodeTypeIfErrorExpr:
30363034 case NodeTypeIfOptional:
30373035 case NodeTypeErrorSetDecl:
3038 case NodeTypeCancel:
30393036 case NodeTypeResume:
30403037 case NodeTypeAwaitExpr:
30413038 case NodeTypeSuspend:
3042 case NodeTypePromiseType:
30433039 case NodeTypeEnumLiteral:
3040 case NodeTypeAnyFrameType:
30443041 zig_unreachable();
30453042 }
30463043}
......@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
30913088 case ZigTypeIdUnion:
30923089 case ZigTypeIdFn:
30933090 case ZigTypeIdBoundFn:
3094 case ZigTypeIdPromise:
30953091 case ZigTypeIdVector:
3092 case ZigTypeIdFnFrame:
3093 case ZigTypeIdAnyFrame:
30963094 return type_entry;
30973095 }
30983096 zig_unreachable();
......@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {
35923590 case ZigTypeIdBoundFn:
35933591 case ZigTypeIdArgTuple:
35943592 case ZigTypeIdOpaque:
3595 case ZigTypeIdPromise:
35963593 case ZigTypeIdVector:
3594 case ZigTypeIdFnFrame:
3595 case ZigTypeIdAnyFrame:
35973596 return false;
35983597 }
35993598 zig_unreachable();
......@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
36493648 case ZigTypeIdInvalid:
36503649 case ZigTypeIdArgTuple:
36513650 case ZigTypeIdOpaque:
3652 case ZigTypeIdPromise:
36533651 case ZigTypeIdVector:
3652 case ZigTypeIdFnFrame:
3653 case ZigTypeIdAnyFrame:
36543654 zig_unreachable();
36553655 }
36563656 zig_unreachable();
......@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
36593659ZigType *get_src_ptr_type(ZigType *type) {
36603660 if (type->id == ZigTypeIdPointer) return type;
36613661 if (type->id == ZigTypeIdFn) return type;
3662 if (type->id == ZigTypeIdPromise) return type;
3662 if (type->id == ZigTypeIdAnyFrame) return type;
36633663 if (type->id == ZigTypeIdOptional) {
36643664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
36653665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
36663666 }
36673667 if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
3668 if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;
3668 if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type;
36693669 }
36703670 return nullptr;
36713671}
......@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {
36813681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);
36823682}
36833683
3684static uint32_t get_async_frame_align_bytes(CodeGen *g) {
3685 uint32_t a = g->pointer_size_bytes * 2;
3686 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
3687 if (a < 8) a = 8;
3688 return a;
3689}
3690
36843691uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
36853692 ZigType *ptr_type = get_src_ptr_type(type);
36863693 if (ptr_type->id == ZigTypeIdPointer) {
......@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
36923699 // when getting the alignment of `?extern fn() void`.
36933700 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html
36943701 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
3695 } else if (ptr_type->id == ZigTypeIdPromise) {
3696 return get_coro_frame_align_bytes(g);
3702 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3703 return get_async_frame_align_bytes(g);
36973704 } else {
36983705 zig_unreachable();
36993706 }
......@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {
37053712 return ptr_type->data.pointer.is_const;
37063713 } else if (ptr_type->id == ZigTypeIdFn) {
37073714 return true;
3708 } else if (ptr_type->id == ZigTypeIdPromise) {
3715 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
37093716 return true;
37103717 } else {
37113718 zig_unreachable();
......@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
37803787 return true;
37813788}
37823789
3783void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
3784 ZigType *fn_type = fn_table_entry->type_entry;
3790static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) {
3791 ZigType *frame_type = get_fn_frame_type(g, fn);
3792 Error err;
3793 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {
3794 fn->anal_state = FnAnalStateInvalid;
3795 return;
3796 }
3797}
3798
3799bool fn_is_async(ZigFn *fn) {
3800 assert(fn->inferred_async_node != nullptr);
3801 assert(fn->inferred_async_node != inferred_async_checking);
3802 return fn->inferred_async_node != inferred_async_none;
3803}
3804
3805static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3806 assert(fn->inferred_async_node != nullptr);
3807 assert(fn->inferred_async_node != inferred_async_checking);
3808 assert(fn->inferred_async_node != inferred_async_none);
3809 if (fn->inferred_async_fn != nullptr) {
3810 ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node,
3811 buf_sprintf("async function call here"));
3812 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);
3813 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {
3814 add_error_note(g, msg, fn->inferred_async_node,
3815 buf_sprintf("async calling convention here"));
3816 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {
3817 add_error_note(g, msg, fn->inferred_async_node,
3818 buf_sprintf("suspends here"));
3819 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3820 add_error_note(g, msg, fn->inferred_async_node,
3821 buf_sprintf("await is a suspend point"));
3822 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&
3823 fn->inferred_async_node->data.fn_call_expr.is_builtin)
3824 {
3825 add_error_note(g, msg, fn->inferred_async_node,
3826 buf_sprintf("@frame() causes function to be async"));
3827 } else {
3828 add_error_note(g, msg, fn->inferred_async_node,
3829 buf_sprintf("suspends here"));
3830 }
3831}
3832
3833// This function resolves functions being inferred async.
3834static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
3835 if (fn->inferred_async_node == inferred_async_checking) {
3836 // TODO call graph cycle detected, disallow the recursion
3837 fn->inferred_async_node = inferred_async_none;
3838 return;
3839 }
3840 if (fn->inferred_async_node == inferred_async_none) {
3841 return;
3842 }
3843 if (fn->inferred_async_node != nullptr) {
3844 if (resolve_frame) {
3845 resolve_async_fn_frame(g, fn);
3846 }
3847 return;
3848 }
3849 fn->inferred_async_node = inferred_async_checking;
3850
3851 bool must_not_be_async = false;
3852 if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) {
3853 must_not_be_async = true;
3854 fn->inferred_async_node = inferred_async_none;
3855 }
3856
3857 for (size_t i = 0; i < fn->call_list.length; i += 1) {
3858 IrInstructionCallGen *call = fn->call_list.at(i);
3859 ZigFn *callee = call->fn_entry;
3860 if (callee == nullptr) {
3861 // TODO function pointer call here, could be anything
3862 continue;
3863 }
3864
3865 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
3866 continue;
3867 if (callee->anal_state == FnAnalStateReady) {
3868 analyze_fn_body(g, callee);
3869 if (callee->anal_state == FnAnalStateInvalid) {
3870 fn->anal_state = FnAnalStateInvalid;
3871 return;
3872 }
3873 }
3874 assert(callee->anal_state == FnAnalStateComplete);
3875 analyze_fn_async(g, callee, true);
3876 if (callee->anal_state == FnAnalStateInvalid) {
3877 fn->anal_state = FnAnalStateInvalid;
3878 return;
3879 }
3880 if (fn_is_async(callee)) {
3881 fn->inferred_async_node = call->base.source_node;
3882 fn->inferred_async_fn = callee;
3883 if (must_not_be_async) {
3884 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3885 buf_sprintf("function with calling convention '%s' cannot be async",
3886 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
3887 add_async_error_notes(g, msg, fn);
3888 fn->anal_state = FnAnalStateInvalid;
3889 return;
3890 }
3891 if (resolve_frame) {
3892 resolve_async_fn_frame(g, fn);
3893 }
3894 return;
3895 }
3896 }
3897 fn->inferred_async_node = inferred_async_none;
3898}
3899
3900static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
3901 ZigType *fn_type = fn->type_entry;
37853902 assert(!fn_type->data.fn.is_generic);
37863903 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
37873904
3788 ZigType *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
3789 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
3790 fn_table_entry->src_implicit_return_type = block_return_type;
3905 ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,
3906 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
3907 fn->src_implicit_return_type = block_return_type;
37913908
3792 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
3909 if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) {
37933910 assert(g->errors.length > 0);
3794 fn_table_entry->anal_state = FnAnalStateInvalid;
3911 fn->anal_state = FnAnalStateInvalid;
37953912 return;
37963913 }
37973914
......@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
37993916 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
38003917 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
38013918 ZigType *inferred_err_set_type;
3802 if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3803 inferred_err_set_type = fn_table_entry->src_implicit_return_type;
3804 } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3805 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
3919 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3920 inferred_err_set_type = fn->src_implicit_return_type;
3921 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3922 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
38063923 } else {
38073924 add_node_error(g, return_type_node,
38083925 buf_sprintf("function with inferred error set must return at least one possible error"));
3809 fn_table_entry->anal_state = FnAnalStateInvalid;
3926 fn->anal_state = FnAnalStateInvalid;
38103927 return;
38113928 }
38123929
38133930 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
38143931 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
3815 fn_table_entry->anal_state = FnAnalStateInvalid;
3932 fn->anal_state = FnAnalStateInvalid;
38163933 return;
38173934 }
38183935 }
......@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
38323949 }
38333950 }
38343951
3952 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
3953 if (cc != CallingConventionUnspecified && cc != CallingConventionAsync &&
3954 fn->inferred_async_node != nullptr &&
3955 fn->inferred_async_node != inferred_async_checking &&
3956 fn->inferred_async_node != inferred_async_none)
3957 {
3958 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3959 buf_sprintf("function with calling convention '%s' cannot be async",
3960 calling_convention_name(cc)));
3961 add_async_error_notes(g, msg, fn);
3962 fn->anal_state = FnAnalStateInvalid;
3963 }
3964
38353965 if (g->verbose_ir) {
3836 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
3837 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
3966 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
3967 ir_print(g, stderr, &fn->analyzed_executable, 4);
38383968 fprintf(stderr, "}\n");
38393969 }
3840
3841 fn_table_entry->anal_state = FnAnalStateComplete;
3970 fn->anal_state = FnAnalStateComplete;
38423971}
38433972
38443973static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
......@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {
40084137 analyze_fn_body(g, fn_entry);
40094138 }
40104139 }
4140
4141 if (g->errors.length != 0) {
4142 return;
4143 }
4144
4145 // second pass over functions for detecting async
4146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
4147 ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);
4148 analyze_fn_async(g, fn_entry, true);
4149 }
40114150}
40124151
40134152ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
......@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {
41034242 case ZigTypeIdErrorSet:
41044243 case ZigTypeIdFn:
41054244 case ZigTypeIdEnum:
4106 case ZigTypeIdPromise:
41074245 case ZigTypeIdVector:
4246 case ZigTypeIdAnyFrame:
41084247 return false;
41094248 case ZigTypeIdArray:
41104249 case ZigTypeIdStruct:
4250 case ZigTypeIdFnFrame:
41114251 return type_has_bits(type_entry);
41124252 case ZigTypeIdErrorUnion:
41134253 return type_has_bits(type_entry->data.error_union.payload_type);
......@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
41434283 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
41444284 result += id->is_var_args ? (uint32_t)1931444534 : 0;
41454285 result += hash_ptr(id->return_type);
4146 result += hash_ptr(id->async_allocator_type);
41474286 result += id->alignment * 0xd3b3f3e2;
41484287 for (size_t i = 0; i < id->param_count; i += 1) {
41494288 FnTypeParamInfo *info = &id->param_info[i];
......@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
41584297 a->return_type != b->return_type ||
41594298 a->is_var_args != b->is_var_args ||
41604299 a->param_count != b->param_count ||
4161 a->alignment != b->alignment ||
4162 a->async_allocator_type != b->async_allocator_type)
4300 a->alignment != b->alignment)
41634301 {
41644302 return false;
41654303 }
......@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43214459 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
43224460 case ZigTypeIdPointer:
43234461 return hash_const_val_ptr(const_val);
4324 case ZigTypeIdPromise:
4325 // TODO better hashing algorithm
4326 return 223048345;
43274462 case ZigTypeIdUndefined:
43284463 return 162837799;
43294464 case ZigTypeIdNull:
......@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43574492 case ZigTypeIdVector:
43584493 // TODO better hashing algorithm
43594494 return 3647867726;
4495 case ZigTypeIdFnFrame:
4496 // TODO better hashing algorithm
4497 return 675741936;
4498 case ZigTypeIdAnyFrame:
4499 // TODO better hashing algorithm
4500 return 3747294894;
43604501 case ZigTypeIdBoundFn:
43614502 case ZigTypeIdInvalid:
43624503 case ZigTypeIdUnreachable:
......@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
43894530 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
43904531 assert(a_val->special == ConstValSpecialStatic);
43914532 assert(b_val->special == ConstValSpecialStatic);
4392 if (!const_values_equal(a->fn_entry->codegen, a_val, b_val)) {
4533 if (!const_values_equal(a->codegen, a_val, b_val)) {
43934534 return false;
43944535 }
43954536 } else {
......@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
44194560 case ZigTypeIdBoundFn:
44204561 case ZigTypeIdFn:
44214562 case ZigTypeIdOpaque:
4422 case ZigTypeIdPromise:
44234563 case ZigTypeIdErrorSet:
44244564 case ZigTypeIdEnum:
4565 case ZigTypeIdFnFrame:
4566 case ZigTypeIdAnyFrame:
44254567 return false;
44264568
44274569 case ZigTypeIdPointer:
......@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {
44894631 case ZigTypeIdBoundFn:
44904632 case ZigTypeIdFn:
44914633 case ZigTypeIdOpaque:
4492 case ZigTypeIdPromise:
44934634 case ZigTypeIdErrorSet:
44944635 case ZigTypeIdEnum:
44954636 case ZigTypeIdPointer:
44964637 case ZigTypeIdVector:
4638 case ZigTypeIdFnFrame:
4639 case ZigTypeIdAnyFrame:
44974640 return true;
44984641
44994642 case ZigTypeIdArray:
......@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
46244767 case ZigTypeIdFn:
46254768 case ZigTypeIdBool:
46264769 case ZigTypeIdFloat:
4627 case ZigTypeIdPromise:
46284770 case ZigTypeIdErrorUnion:
4771 case ZigTypeIdFnFrame:
4772 case ZigTypeIdAnyFrame:
46294773 return OnePossibleValueNo;
46304774 case ZigTypeIdUndefined:
46314775 case ZigTypeIdNull:
......@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
47134857 case ZigTypeIdFloat:
47144858 case ZigTypeIdVoid:
47154859 case ZigTypeIdUnreachable:
4716 case ZigTypeIdPromise:
4860 case ZigTypeIdFnFrame:
4861 case ZigTypeIdAnyFrame:
47174862 return ReqCompTimeNo;
47184863 }
47194864 zig_unreachable();
......@@ -5032,6 +5177,223 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
50325177 return type_resolve(g, type_entry, ResolveStatusSizeKnown);
50335178}
50345179
5180static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
5181 if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync)
5182 return orig_fn_type;
5183
5184 ZigType *fn_type = allocate_nonzero<ZigType>(1);
5185 *fn_type = *orig_fn_type;
5186 fn_type->data.fn.fn_type_id.cc = CallingConventionAsync;
5187 fn_type->llvm_type = nullptr;
5188 fn_type->llvm_di_type = nullptr;
5189
5190 return fn_type;
5191}
5192
5193static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5194 Error err;
5195
5196 if (frame_type->data.frame.locals_struct != nullptr)
5197 return ErrorNone;
5198
5199 ZigFn *fn = frame_type->data.frame.fn;
5200 assert(!fn->type_entry->data.fn.is_generic);
5201
5202 switch (fn->anal_state) {
5203 case FnAnalStateInvalid:
5204 return ErrorSemanticAnalyzeFail;
5205 case FnAnalStateComplete:
5206 break;
5207 case FnAnalStateReady:
5208 analyze_fn_body(g, fn);
5209 if (fn->anal_state == FnAnalStateInvalid)
5210 return ErrorSemanticAnalyzeFail;
5211 break;
5212 case FnAnalStateProbing: {
5213 ErrorMsg *msg = add_node_error(g, fn->proto_node,
5214 buf_sprintf("cannot resolve '%s': function not fully analyzed yet",
5215 buf_ptr(&frame_type->name)));
5216 ir_add_analysis_trace(fn->ir_executable.analysis, msg,
5217 buf_sprintf("depends on its own frame here"));
5218 return ErrorSemanticAnalyzeFail;
5219 }
5220 }
5221 analyze_fn_async(g, fn, false);
5222 if (fn->anal_state == FnAnalStateInvalid)
5223 return ErrorSemanticAnalyzeFail;
5224
5225 if (!fn_is_async(fn)) {
5226 ZigType *fn_type = fn->type_entry;
5227 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5228 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5229
5230 // label (grep this): [fn_frame_struct_layout]
5231 ZigList<SrcField> fields = {};
5232
5233 fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0});
5234 fields.append({"@resume_index", g->builtin_types.entry_usize, 0});
5235 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
5236
5237 fields.append({"@result_ptr_callee", ptr_return_type, 0});
5238 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
5239 fields.append({"@result", fn_type_id->return_type, 0});
5240
5241 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
5242 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
5243 fields.append({"@ptr_stack_trace_callee", ptr_to_stack_trace_type, 0});
5244 fields.append({"@ptr_stack_trace_awaiter", ptr_to_stack_trace_type, 0});
5245
5246 fields.append({"@stack_trace", get_stack_trace_type(g), 0});
5247 fields.append({"@instruction_addresses",
5248 get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
5249 }
5250
5251 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5252 fields.items, fields.length, target_fn_align(g->zig_target));
5253 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5254 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5255 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5256
5257 return ErrorNone;
5258 }
5259
5260 ZigType *fn_type = get_async_fn_type(g, fn->type_entry);
5261
5262 if (fn->analyzed_executable.need_err_code_spill) {
5263 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5264 alloca_gen->base.id = IrInstructionIdAllocaGen;
5265 alloca_gen->base.source_node = fn->proto_node;
5266 alloca_gen->base.scope = fn->child_scope;
5267 alloca_gen->base.value.type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
5268 alloca_gen->base.ref_count = 1;
5269 alloca_gen->name_hint = "";
5270 fn->alloca_gen_list.append(alloca_gen);
5271 fn->err_code_spill = &alloca_gen->base;
5272 }
5273
5274 for (size_t i = 0; i < fn->call_list.length; i += 1) {
5275 IrInstructionCallGen *call = fn->call_list.at(i);
5276 ZigFn *callee = call->fn_entry;
5277 if (callee == nullptr) {
5278 add_node_error(g, call->base.source_node,
5279 buf_sprintf("function is not comptime-known; @asyncCall required"));
5280 return ErrorSemanticAnalyzeFail;
5281 }
5282 if (callee->body_node == nullptr) {
5283 continue;
5284 }
5285 if (callee->anal_state == FnAnalStateProbing) {
5286 ErrorMsg *msg = add_node_error(g, fn->proto_node,
5287 buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name)));
5288 ErrorMsg *note = add_error_note(g, msg, call->base.source_node,
5289 buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name)));
5290 ir_add_analysis_trace(callee->ir_executable.analysis, note,
5291 buf_sprintf("depends on the frame here"));
5292 return ErrorSemanticAnalyzeFail;
5293 }
5294
5295 analyze_fn_body(g, callee);
5296 if (callee->anal_state == FnAnalStateInvalid) {
5297 frame_type->data.frame.locals_struct = g->builtin_types.entry_invalid;
5298 return ErrorSemanticAnalyzeFail;
5299 }
5300 analyze_fn_async(g, callee, true);
5301 if (!fn_is_async(callee))
5302 continue;
5303
5304 ZigType *callee_frame_type = get_fn_frame_type(g, callee);
5305
5306 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5307 alloca_gen->base.id = IrInstructionIdAllocaGen;
5308 alloca_gen->base.source_node = call->base.source_node;
5309 alloca_gen->base.scope = call->base.scope;
5310 alloca_gen->base.value.type = get_pointer_to_type(g, callee_frame_type, false);
5311 alloca_gen->base.ref_count = 1;
5312 alloca_gen->name_hint = "";
5313 fn->alloca_gen_list.append(alloca_gen);
5314 call->frame_result_loc = &alloca_gen->base;
5315 }
5316 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
5317 ZigType *ptr_return_type = get_pointer_to_type(g, fn_type_id->return_type, false);
5318
5319 // label (grep this): [fn_frame_struct_layout]
5320 ZigList<SrcField> fields = {};
5321
5322 fields.append({"@fn_ptr", fn_type, 0});
5323 fields.append({"@resume_index", g->builtin_types.entry_usize, 0});
5324 fields.append({"@awaiter", g->builtin_types.entry_usize, 0});
5325
5326 fields.append({"@result_ptr_callee", ptr_return_type, 0});
5327 fields.append({"@result_ptr_awaiter", ptr_return_type, 0});
5328 fields.append({"@result", fn_type_id->return_type, 0});
5329
5330 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
5331 ZigType *ptr_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
5332 fields.append({"@ptr_stack_trace_callee", ptr_stack_trace_type, 0});
5333 fields.append({"@ptr_stack_trace_awaiter", ptr_stack_trace_type, 0});
5334 }
5335
5336 for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) {
5337 FnTypeParamInfo *param_info = &fn_type_id->param_info[arg_i];
5338 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
5339 Buf *param_name;
5340 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
5341 if (param_decl_node && !is_var_args) {
5342 param_name = param_decl_node->data.param_decl.name;
5343 } else {
5344 param_name = buf_sprintf("@arg%" ZIG_PRI_usize, arg_i);
5345 }
5346 ZigType *param_type = param_info->type;
5347
5348 fields.append({buf_ptr(param_name), param_type, 0});
5349 }
5350
5351 if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) {
5352 fields.append({"@stack_trace", get_stack_trace_type(g), 0});
5353 fields.append({"@instruction_addresses",
5354 get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0});
5355 }
5356
5357 for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
5358 IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
5359 instruction->field_index = SIZE_MAX;
5360 ZigType *ptr_type = instruction->base.value.type;
5361 assert(ptr_type->id == ZigTypeIdPointer);
5362 ZigType *child_type = ptr_type->data.pointer.child_type;
5363 if (!type_has_bits(child_type))
5364 continue;
5365 if (instruction->base.ref_count == 0)
5366 continue;
5367 if (instruction->base.value.special != ConstValSpecialRuntime) {
5368 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
5369 ConstValSpecialRuntime)
5370 {
5371 continue;
5372 }
5373 }
5374 if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
5375 return err;
5376 }
5377 const char *name;
5378 if (*instruction->name_hint == 0) {
5379 name = buf_ptr(buf_sprintf("@local%" ZIG_PRI_usize, alloca_i));
5380 } else {
5381 name = buf_ptr(buf_sprintf("%s.%" ZIG_PRI_usize, instruction->name_hint, alloca_i));
5382 }
5383 instruction->field_index = fields.length;
5384
5385 fields.append({name, child_type, instruction->align});
5386 }
5387
5388
5389 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
5390 fields.items, fields.length, target_fn_align(g->zig_target));
5391 frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size;
5392 frame_type->abi_align = frame_type->data.frame.locals_struct->abi_align;
5393 frame_type->size_in_bits = frame_type->data.frame.locals_struct->size_in_bits;
5394 return ErrorNone;
5395}
5396
50355397Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50365398 if (type_is_invalid(ty))
50375399 return ErrorSemanticAnalyzeFail;
......@@ -5056,6 +5418,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50565418 return resolve_enum_zero_bits(g, ty);
50575419 } else if (ty->id == ZigTypeIdUnion) {
50585420 return resolve_union_alignment(g, ty);
5421 } else if (ty->id == ZigTypeIdFnFrame) {
5422 return resolve_async_frame(g, ty);
50595423 }
50605424 return ErrorNone;
50615425 case ResolveStatusSizeKnown:
......@@ -5065,6 +5429,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
50655429 return resolve_enum_zero_bits(g, ty);
50665430 } else if (ty->id == ZigTypeIdUnion) {
50675431 return resolve_union_type(g, ty);
5432 } else if (ty->id == ZigTypeIdFnFrame) {
5433 return resolve_async_frame(g, ty);
50685434 }
50695435 return ErrorNone;
50705436 case ResolveStatusLLVMFwdDecl:
......@@ -5259,6 +5625,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
52595625 return false;
52605626 }
52615627 return true;
5628 case ZigTypeIdFnFrame:
5629 zig_panic("TODO");
5630 case ZigTypeIdAnyFrame:
5631 zig_panic("TODO");
52625632 case ZigTypeIdUndefined:
52635633 zig_panic("TODO");
52645634 case ZigTypeIdNull:
......@@ -5279,7 +5649,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
52795649 case ZigTypeIdBoundFn:
52805650 case ZigTypeIdInvalid:
52815651 case ZigTypeIdUnreachable:
5282 case ZigTypeIdPromise:
52835652 zig_unreachable();
52845653 }
52855654 zig_unreachable();
......@@ -5612,8 +5981,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
56125981 buf_appendf(buf, "(args value)");
56135982 return;
56145983 }
5615 case ZigTypeIdPromise:
5616 zig_unreachable();
5984 case ZigTypeIdFnFrame:
5985 buf_appendf(buf, "(TODO: async function frame value)");
5986 return;
5987
5988 case ZigTypeIdAnyFrame:
5989 buf_appendf(buf, "(TODO: anyframe value)");
5990 return;
5991
56175992 }
56185993 zig_unreachable();
56195994}
......@@ -5627,6 +6002,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
56276002 entry->llvm_type = LLVMIntType(size_in_bits);
56286003 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
56296004 entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);
6005
6006 if (size_in_bits >= 128) {
6007 // Override the incorrect alignment reported by LLVM. Clang does this as well.
6008 // On x86_64 there are some instructions like CMPXCHG16B which require this.
6009 // On all targets, integers 128 bits and above have ABI alignment of 16.
6010 // See: https://github.com/ziglang/zig/issues/2987
6011 assert(entry->abi_align == 8); // if this trips we can remove the workaround
6012 entry->abi_align = 16;
6013 }
56306014 }
56316015
56326016 const char u_or_i = is_signed ? 'i' : 'u';
......@@ -5660,7 +6044,8 @@ uint32_t type_id_hash(TypeId x) {
56606044 case ZigTypeIdFn:
56616045 case ZigTypeIdBoundFn:
56626046 case ZigTypeIdArgTuple:
5663 case ZigTypeIdPromise:
6047 case ZigTypeIdFnFrame:
6048 case ZigTypeIdAnyFrame:
56646049 zig_unreachable();
56656050 case ZigTypeIdErrorUnion:
56666051 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
......@@ -5702,7 +6087,6 @@ bool type_id_eql(TypeId a, TypeId b) {
57026087 case ZigTypeIdUndefined:
57036088 case ZigTypeIdNull:
57046089 case ZigTypeIdOptional:
5705 case ZigTypeIdPromise:
57066090 case ZigTypeIdErrorSet:
57076091 case ZigTypeIdEnum:
57086092 case ZigTypeIdUnion:
......@@ -5710,6 +6094,8 @@ bool type_id_eql(TypeId a, TypeId b) {
57106094 case ZigTypeIdBoundFn:
57116095 case ZigTypeIdArgTuple:
57126096 case ZigTypeIdOpaque:
6097 case ZigTypeIdFnFrame:
6098 case ZigTypeIdAnyFrame:
57136099 zig_unreachable();
57146100 case ZigTypeIdErrorUnion:
57156101 return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&
......@@ -5875,7 +6261,8 @@ static const ZigTypeId all_type_ids[] = {
58756261 ZigTypeIdBoundFn,
58766262 ZigTypeIdArgTuple,
58776263 ZigTypeIdOpaque,
5878 ZigTypeIdPromise,
6264 ZigTypeIdFnFrame,
6265 ZigTypeIdAnyFrame,
58796266 ZigTypeIdVector,
58806267 ZigTypeIdEnumLiteral,
58816268};
......@@ -5939,12 +6326,14 @@ size_t type_id_index(ZigType *entry) {
59396326 return 20;
59406327 case ZigTypeIdOpaque:
59416328 return 21;
5942 case ZigTypeIdPromise:
6329 case ZigTypeIdFnFrame:
59436330 return 22;
5944 case ZigTypeIdVector:
6331 case ZigTypeIdAnyFrame:
59456332 return 23;
5946 case ZigTypeIdEnumLiteral:
6333 case ZigTypeIdVector:
59476334 return 24;
6335 case ZigTypeIdEnumLiteral:
6336 return 25;
59486337 }
59496338 zig_unreachable();
59506339}
......@@ -5999,10 +6388,12 @@ const char *type_id_name(ZigTypeId id) {
59996388 return "ArgTuple";
60006389 case ZigTypeIdOpaque:
60016390 return "Opaque";
6002 case ZigTypeIdPromise:
6003 return "Promise";
60046391 case ZigTypeIdVector:
60056392 return "Vector";
6393 case ZigTypeIdFnFrame:
6394 return "Frame";
6395 case ZigTypeIdAnyFrame:
6396 return "AnyFrame";
60066397 }
60076398 zig_unreachable();
60086399}
......@@ -6067,19 +6458,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {
60676458 return err_set_type->data.error_set.err_count == UINT32_MAX;
60686459}
60696460
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
60776461bool type_can_fail(ZigType *type_entry) {
60786462 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;
60796463}
60806464
60816465bool fn_type_can_fail(FnTypeId *fn_type_id) {
6082 return type_can_fail(fn_type_id->return_type) || fn_type_id->cc == CallingConventionAsync;
6466 return type_can_fail(fn_type_id->return_type);
60836467}
60846468
60856469// ErrorNone - result pointer has the type
......@@ -6449,7 +6833,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
64496833 type->data.structure.resolve_status = ResolveStatusLLVMFull;
64506834}
64516835
6452static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status) {
6836static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveStatus wanted_resolve_status,
6837 ZigType *async_frame_type)
6838{
64536839 assert(struct_type->id == ZigTypeIdStruct);
64546840 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);
64556841 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);
......@@ -6486,10 +6872,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64866872 }
64876873
64886874 size_t field_count = struct_type->data.structure.src_field_count;
6489 size_t gen_field_count = struct_type->data.structure.gen_field_count;
6490 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);
6875 // Every field could potentially have a generated padding field after it.
6876 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count * 2);
64916877
6492 size_t gen_field_index = 0;
64936878 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
64946879 size_t packed_bits_offset = 0;
64956880 size_t first_packed_bits_offset_misalign = SIZE_MAX;
......@@ -6497,20 +6882,36 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64976882
64986883 // trigger all the recursive get_llvm_type calls
64996884 for (size_t i = 0; i < field_count; i += 1) {
6500 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6501 ZigType *field_type = type_struct_field->type_entry;
6885 TypeStructField *field = &struct_type->data.structure.fields[i];
6886 ZigType *field_type = field->type_entry;
65026887 if (!type_has_bits(field_type))
65036888 continue;
65046889 (void)get_llvm_type(g, field_type);
65056890 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;
65066891 }
65076892
6508 for (size_t i = 0; i < field_count; i += 1) {
6509 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6510 ZigType *field_type = type_struct_field->type_entry;
6893 size_t gen_field_index = 0;
65116894
6895 // Calculate what LLVM thinks the ABI align of the struct will be. We do this to avoid
6896 // inserting padding bytes where LLVM would do it automatically.
6897 size_t llvm_struct_abi_align = 0;
6898 for (size_t i = 0; i < field_count; i += 1) {
6899 ZigType *field_type = struct_type->data.structure.fields[i].type_entry;
65126900 if (!type_has_bits(field_type))
65136901 continue;
6902 LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type);
6903 size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type);
6904 llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align);
6905 }
6906
6907 for (size_t i = 0; i < field_count; i += 1) {
6908 TypeStructField *field = &struct_type->data.structure.fields[i];
6909 ZigType *field_type = field->type_entry;
6910
6911 if (!type_has_bits(field_type)) {
6912 field->gen_index = SIZE_MAX;
6913 continue;
6914 }
65146915
65156916 if (packed) {
65166917 size_t field_size_in_bits = type_size_bits(g, field_type);
......@@ -6537,12 +6938,61 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65376938 }
65386939 packed_bits_offset = next_packed_bits_offset;
65396940 } else {
6540 element_types[gen_field_index] = get_llvm_type(g, field_type);
6541
6941 LLVMTypeRef llvm_type;
6942 if (i == 0 && async_frame_type != nullptr) {
6943 assert(async_frame_type->id == ZigTypeIdFnFrame);
6944 assert(field_type->id == ZigTypeIdFn);
6945 resolve_llvm_types_fn(g, async_frame_type->data.frame.fn);
6946 llvm_type = LLVMPointerType(async_frame_type->data.frame.fn->raw_type_ref, 0);
6947 } else {
6948 llvm_type = get_llvm_type(g, field_type);
6949 }
6950 element_types[gen_field_index] = llvm_type;
6951 field->gen_index = gen_field_index;
65426952 gen_field_index += 1;
6953
6954 // find the next non-zero-byte field for offset calculations
6955 size_t next_src_field_index = i + 1;
6956 for (; next_src_field_index < field_count; next_src_field_index += 1) {
6957 if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
6958 break;
6959 }
6960 size_t next_abi_align;
6961 if (next_src_field_index == field_count) {
6962 next_abi_align = struct_type->abi_align;
6963 } else {
6964 if (struct_type->data.structure.fields[next_src_field_index].align == 0) {
6965 next_abi_align = struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;
6966 } else {
6967 next_abi_align = struct_type->data.structure.fields[next_src_field_index].align;
6968 }
6969 }
6970 size_t llvm_next_abi_align = (next_src_field_index == field_count) ?
6971 llvm_struct_abi_align :
6972 LLVMABIAlignmentOfType(g->target_data_ref,
6973 get_llvm_type(g, struct_type->data.structure.fields[next_src_field_index].type_entry));
6974
6975 size_t next_offset = next_field_offset(field->offset, struct_type->abi_align,
6976 field_type->abi_size, next_abi_align);
6977 size_t llvm_next_offset = next_field_offset(field->offset, llvm_struct_abi_align,
6978 LLVMABISizeOfType(g->target_data_ref, llvm_type), llvm_next_abi_align);
6979
6980 assert(next_offset >= llvm_next_offset);
6981 if (next_offset > llvm_next_offset) {
6982 size_t pad_bytes = next_offset - (field->offset + field_type->abi_size);
6983 if (pad_bytes != 0) {
6984 LLVMTypeRef pad_llvm_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
6985 element_types[gen_field_index] = pad_llvm_type;
6986 gen_field_index += 1;
6987 }
6988 }
65436989 }
65446990 debug_field_count += 1;
65456991 }
6992 if (!packed) {
6993 struct_type->data.structure.gen_field_count = gen_field_index;
6994 }
6995
65466996 if (first_packed_bits_offset_misalign != SIZE_MAX) {
65476997 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
65486998 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);
......@@ -6551,19 +7001,20 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65517001 }
65527002
65537003 if (type_has_bits(struct_type)) {
6554 LLVMStructSetBody(struct_type->llvm_type, element_types, (unsigned)gen_field_count, packed);
7004 LLVMStructSetBody(struct_type->llvm_type, element_types,
7005 (unsigned)struct_type->data.structure.gen_field_count, packed);
65557006 }
65567007
65577008 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
65587009 size_t debug_field_index = 0;
65597010 for (size_t i = 0; i < field_count; i += 1) {
6560 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6561 size_t gen_field_index = type_struct_field->gen_index;
7011 TypeStructField *field = &struct_type->data.structure.fields[i];
7012 size_t gen_field_index = field->gen_index;
65627013 if (gen_field_index == SIZE_MAX) {
65637014 continue;
65647015 }
65657016
6566 ZigType *field_type = type_struct_field->type_entry;
7017 ZigType *field_type = field->type_entry;
65677018
65687019 // if the field is a function, actually the debug info should be a pointer.
65697020 ZigLLVMDIType *field_di_type;
......@@ -6581,13 +7032,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65817032 uint64_t debug_align_in_bits;
65827033 uint64_t debug_offset_in_bits;
65837034 if (packed) {
6584 debug_size_in_bits = type_struct_field->type_entry->size_in_bits;
6585 debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;
6586 debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;
7035 debug_size_in_bits = field->type_entry->size_in_bits;
7036 debug_align_in_bits = 8 * field->type_entry->abi_align;
7037 debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host;
65877038 } else {
65887039 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);
65897040 debug_align_in_bits = 8 * field_type->abi_align;
6590 debug_offset_in_bits = 8 * type_struct_field->offset;
7041 debug_offset_in_bits = 8 * field->offset;
65917042 }
65927043 unsigned line;
65937044 if (decl_node != nullptr) {
......@@ -6597,7 +7048,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
65977048 line = 0;
65987049 }
65997050 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
6600 ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(type_struct_field->name),
7051 ZigLLVMTypeToScope(struct_type->llvm_di_type), buf_ptr(field->name),
66017052 di_file, line,
66027053 debug_size_in_bits,
66037054 debug_align_in_bits,
......@@ -6838,7 +7289,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
68387289 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
68397290}
68407291
6841static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
7292static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
68427293 if (type->llvm_di_type != nullptr) return;
68437294
68447295 if (!type_has_bits(type)) {
......@@ -6867,7 +7318,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
68677318 uint64_t debug_align_in_bits = 8*type->abi_align;
68687319 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,
68697320 debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));
6870 assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFull));
7321 assertNoError(type_resolve(g, elem_type, wanted_resolve_status));
68717322 } else {
68727323 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
68737324 LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);
......@@ -6993,10 +7444,17 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
69937444 } else {
69947445 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
69957446 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
6996 LLVMTypeRef elem_types[2];
7447 LLVMTypeRef elem_types[3];
69977448 elem_types[err_union_err_index] = err_set_llvm_type;
69987449 elem_types[err_union_payload_index] = payload_llvm_type;
7450
69997451 type->llvm_type = LLVMStructType(elem_types, 2, false);
7452 if (LLVMABISizeOfType(g->target_data_ref, type->llvm_type) != type->abi_size) {
7453 // we need to do our own padding
7454 type->data.error_union.pad_llvm_type = LLVMArrayType(LLVMInt8Type(), type->data.error_union.pad_bytes);
7455 elem_types[2] = type->data.error_union.pad_llvm_type;
7456 type->llvm_type = LLVMStructType(elem_types, 3, false);
7457 }
70007458
70017459 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
70027460 ZigLLVMDIFile *di_file = nullptr;
......@@ -7017,20 +7475,21 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
70177475 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
70187476 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
70197477
7020 ZigLLVMDIType *di_element_types[] = {
7021 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
7478 ZigLLVMDIType *di_element_types[2];
7479 di_element_types[err_union_err_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
7480 ZigLLVMTypeToScope(type->llvm_di_type),
70227481 "tag", di_file, line,
70237482 tag_debug_size_in_bits,
70247483 tag_debug_align_in_bits,
70257484 tag_offset_in_bits,
7026 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type)),
7027 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),
7485 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type));
7486 di_element_types[err_union_payload_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
7487 ZigLLVMTypeToScope(type->llvm_di_type),
70287488 "value", di_file, line,
70297489 value_debug_size_in_bits,
70307490 value_debug_align_in_bits,
70317491 value_offset_in_bits,
7032 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type)),
7033 };
7492 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type));
70347493
70357494 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
70367495 compile_unit_scope,
......@@ -7067,7 +7526,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
70677526 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
70687527}
70697528
7070static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7529static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
70717530 if (fn_type->llvm_di_type != nullptr) return;
70727531
70737532 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -7084,67 +7543,73 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
70847543 // +1 for maybe first argument the error return trace
70857544 // +2 for maybe arguments async allocator and error code pointer
70867545 ZigList<ZigLLVMDIType *> param_di_types = {};
7087 param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
70887546 ZigType *gen_return_type;
70897547 if (is_async) {
7090 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
7548 gen_return_type = g->builtin_types.entry_void;
7549 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70917550 } else if (!type_has_bits(fn_type_id->return_type)) {
70927551 gen_return_type = g->builtin_types.entry_void;
7552 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70937553 } else if (first_arg_return) {
7554 gen_return_type = g->builtin_types.entry_void;
7555 param_di_types.append(get_llvm_di_type(g, gen_return_type));
70947556 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
70957557 gen_param_types.append(get_llvm_type(g, gen_type));
70967558 param_di_types.append(get_llvm_di_type(g, gen_type));
7097 gen_return_type = g->builtin_types.entry_void;
70987559 } else {
70997560 gen_return_type = fn_type_id->return_type;
7561 param_di_types.append(get_llvm_di_type(g, gen_return_type));
71007562 }
71017563 fn_type->data.fn.gen_return_type = gen_return_type;
71027564
7103 if (prefix_arg_error_return_trace) {
7104 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
7565 if (prefix_arg_error_return_trace && !is_async) {
7566 ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
71057567 gen_param_types.append(get_llvm_type(g, gen_type));
71067568 param_di_types.append(get_llvm_di_type(g, gen_type));
71077569 }
71087570 if (is_async) {
7109 {
7110 // async allocator param
7111 ZigType *gen_type = fn_type_id->async_allocator_type;
7112 gen_param_types.append(get_llvm_type(g, gen_type));
7113 param_di_types.append(get_llvm_di_type(g, gen_type));
7114 }
7571 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(2);
71157572
7116 {
7117 // error code pointer
7118 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
7119 gen_param_types.append(get_llvm_type(g, gen_type));
7120 param_di_types.append(get_llvm_di_type(g, gen_type));
7121 }
7122 }
7573 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7574 gen_param_types.append(get_llvm_type(g, frame_type));
7575 param_di_types.append(get_llvm_di_type(g, frame_type));
71237576
7124 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7125 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
7126 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
7127 ZigType *type_entry = src_param_info->type;
7128 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
7577 fn_type->data.fn.gen_param_info[0].src_index = 0;
7578 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7579 fn_type->data.fn.gen_param_info[0].type = frame_type;
71297580
7130 gen_param_info->src_index = i;
7131 gen_param_info->gen_index = SIZE_MAX;
7581 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7582 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
71327583
7133 if (is_c_abi || !type_has_bits(type_entry))
7134 continue;
7584 fn_type->data.fn.gen_param_info[1].src_index = 1;
7585 fn_type->data.fn.gen_param_info[1].gen_index = 1;
7586 fn_type->data.fn.gen_param_info[1].type = g->builtin_types.entry_usize;
7587 } else {
7588 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7589 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
7590 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
7591 ZigType *type_entry = src_param_info->type;
7592 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
71357593
7136 ZigType *gen_type;
7137 if (handle_is_ptr(type_entry)) {
7138 gen_type = get_pointer_to_type(g, type_entry, true);
7139 gen_param_info->is_byval = true;
7140 } else {
7141 gen_type = type_entry;
7142 }
7143 gen_param_info->gen_index = gen_param_types.length;
7144 gen_param_info->type = gen_type;
7145 gen_param_types.append(get_llvm_type(g, gen_type));
7594 gen_param_info->src_index = i;
7595 gen_param_info->gen_index = SIZE_MAX;
71467596
7147 param_di_types.append(get_llvm_di_type(g, gen_type));
7597 if (is_c_abi || !type_has_bits(type_entry))
7598 continue;
7599
7600 ZigType *gen_type;
7601 if (handle_is_ptr(type_entry)) {
7602 gen_type = get_pointer_to_type(g, type_entry, true);
7603 gen_param_info->is_byval = true;
7604 } else {
7605 gen_type = type_entry;
7606 }
7607 gen_param_info->gen_index = gen_param_types.length;
7608 gen_param_info->type = gen_type;
7609 gen_param_types.append(get_llvm_type(g, gen_type));
7610
7611 param_di_types.append(get_llvm_di_type(g, gen_type));
7612 }
71487613 }
71497614
71507615 if (is_c_abi) {
......@@ -7160,6 +7625,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
71607625 for (size_t i = 0; i < gen_param_types.length; i += 1) {
71617626 assert(gen_param_types.items[i] != nullptr);
71627627 }
7628
71637629 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
71647630 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
71657631 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
......@@ -7169,6 +7635,40 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
71697635 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
71707636}
71717637
7638void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn) {
7639 Error err;
7640 if (fn->raw_di_type != nullptr) return;
7641
7642 ZigType *fn_type = fn->type_entry;
7643 if (!fn_is_async(fn)) {
7644 resolve_llvm_types_fn_type(g, fn_type);
7645 fn->raw_type_ref = fn_type->data.fn.raw_type_ref;
7646 fn->raw_di_type = fn_type->data.fn.raw_di_type;
7647 return;
7648 }
7649
7650 ZigType *gen_return_type = g->builtin_types.entry_void;
7651 ZigList<ZigLLVMDIType *> param_di_types = {};
7652 ZigList<LLVMTypeRef> gen_param_types = {};
7653 // first "parameter" is return value
7654 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7655
7656 ZigType *frame_type = get_fn_frame_type(g, fn);
7657 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7658 if ((err = type_resolve(g, ptr_type, ResolveStatusLLVMFwdDecl)))
7659 zig_unreachable();
7660 gen_param_types.append(ptr_type->llvm_type);
7661 param_di_types.append(ptr_type->llvm_di_type);
7662
7663 // this parameter is used to pass the result pointer when await completes
7664 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7665 param_di_types.append(get_llvm_di_type(g, g->builtin_types.entry_usize));
7666
7667 fn->raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7668 gen_param_types.items, gen_param_types.length, false);
7669 fn->raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
7670}
7671
71727672static void resolve_llvm_types_anyerror(CodeGen *g) {
71737673 ZigType *entry = g->builtin_types.entry_global_error_set;
71747674 entry->llvm_type = get_llvm_type(g, g->err_tag_type);
......@@ -7193,6 +7693,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
71937693 get_llvm_di_type(g, g->err_tag_type), "");
71947694}
71957695
7696static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {
7697 ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;
7698 resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);
7699 frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
7700 frame_type->llvm_di_type = frame_type->data.frame.locals_struct->llvm_di_type;
7701}
7702
7703static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, ResolveStatus wanted_resolve_status) {
7704 if (any_frame_type->llvm_di_type != nullptr) return;
7705
7706 Buf *name = buf_sprintf("(%s header)", buf_ptr(&any_frame_type->name));
7707 LLVMTypeRef frame_header_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
7708 any_frame_type->llvm_type = LLVMPointerType(frame_header_type, 0);
7709
7710 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
7711 ZigLLVMDIFile *di_file = nullptr;
7712 ZigLLVMDIScope *di_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7713 unsigned line = 0;
7714 ZigLLVMDIType *frame_header_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
7715 dwarf_kind, buf_ptr(name), di_scope, di_file, line);
7716 any_frame_type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, frame_header_di_type,
7717 8*g->pointer_size_bytes, 8*g->builtin_types.entry_usize->abi_align, buf_ptr(&any_frame_type->name));
7718
7719 LLVMTypeRef llvm_void = LLVMVoidType();
7720 LLVMTypeRef arg_types[] = {any_frame_type->llvm_type, g->builtin_types.entry_usize->llvm_type};
7721 LLVMTypeRef fn_type = LLVMFunctionType(llvm_void, arg_types, 2, false);
7722 LLVMTypeRef usize_type_ref = get_llvm_type(g, g->builtin_types.entry_usize);
7723 ZigLLVMDIType *usize_di_type = get_llvm_di_type(g, g->builtin_types.entry_usize);
7724 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7725
7726 ZigType *result_type = any_frame_type->data.any_frame.result_type;
7727 ZigType *ptr_result_type = (result_type == nullptr) ? nullptr : get_pointer_to_type(g, result_type, false);
7728 LLVMTypeRef ptr_fn_llvm_type = LLVMPointerType(fn_type, 0);
7729 if (result_type == nullptr) {
7730 g->anyframe_fn_type = ptr_fn_llvm_type;
7731 }
7732
7733 ZigList<LLVMTypeRef> field_types = {};
7734 ZigList<ZigLLVMDIType *> di_element_types = {};
7735
7736 // label (grep this): [fn_frame_struct_layout]
7737 field_types.append(ptr_fn_llvm_type); // fn_ptr
7738 field_types.append(usize_type_ref); // resume_index
7739 field_types.append(usize_type_ref); // awaiter
7740
7741 bool have_result_type = result_type != nullptr && type_has_bits(result_type);
7742 if (have_result_type) {
7743 field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_callee
7744 field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_awaiter
7745 field_types.append(get_llvm_type(g, result_type)); // result
7746 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
7747 ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false);
7748 field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_callee
7749 field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_awaiter
7750 }
7751 }
7752 LLVMStructSetBody(frame_header_type, field_types.items, field_types.length, false);
7753
7754 di_element_types.append(
7755 ZigLLVMCreateDebugMemberType(g->dbuilder,
7756 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "fn_ptr",
7757 di_file, line,
7758 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7759 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7760 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7761 ZigLLVM_DIFlags_Zero, usize_di_type));
7762 di_element_types.append(
7763 ZigLLVMCreateDebugMemberType(g->dbuilder,
7764 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "resume_index",
7765 di_file, line,
7766 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7767 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7768 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7769 ZigLLVM_DIFlags_Zero, usize_di_type));
7770 di_element_types.append(
7771 ZigLLVMCreateDebugMemberType(g->dbuilder,
7772 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "awaiter",
7773 di_file, line,
7774 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7775 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7776 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7777 ZigLLVM_DIFlags_Zero, usize_di_type));
7778
7779 if (have_result_type) {
7780 di_element_types.append(
7781 ZigLLVMCreateDebugMemberType(g->dbuilder,
7782 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_callee",
7783 di_file, line,
7784 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7785 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7786 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7787 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type)));
7788 di_element_types.append(
7789 ZigLLVMCreateDebugMemberType(g->dbuilder,
7790 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result_ptr_awaiter",
7791 di_file, line,
7792 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7793 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7794 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7795 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_result_type)));
7796 di_element_types.append(
7797 ZigLLVMCreateDebugMemberType(g->dbuilder,
7798 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "result",
7799 di_file, line,
7800 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7801 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7802 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7803 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, result_type)));
7804
7805 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
7806 ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false);
7807 di_element_types.append(
7808 ZigLLVMCreateDebugMemberType(g->dbuilder,
7809 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_callee",
7810 di_file, line,
7811 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7812 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7813 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7814 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace)));
7815 di_element_types.append(
7816 ZigLLVMCreateDebugMemberType(g->dbuilder,
7817 ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_awaiter",
7818 di_file, line,
7819 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7820 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)),
7821 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length),
7822 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace)));
7823 }
7824 };
7825
7826 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
7827 compile_unit_scope, buf_ptr(name),
7828 di_file, line,
7829 8*LLVMABISizeOfType(g->target_data_ref, frame_header_type),
7830 8*LLVMABIAlignmentOfType(g->target_data_ref, frame_header_type),
7831 ZigLLVM_DIFlags_Zero,
7832 nullptr, di_element_types.items, di_element_types.length, 0, nullptr, "");
7833
7834 ZigLLVMReplaceTemporary(g->dbuilder, frame_header_di_type, replacement_di_type);
7835}
7836
71967837static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
71977838 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
71987839 assert(wanted_resolve_status > ResolveStatusSizeKnown);
......@@ -7218,20 +7859,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72187859 if (type->data.structure.is_slice)
72197860 return resolve_llvm_types_slice(g, type, wanted_resolve_status);
72207861 else
7221 return resolve_llvm_types_struct(g, type, wanted_resolve_status);
7862 return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr);
72227863 case ZigTypeIdEnum:
72237864 return resolve_llvm_types_enum(g, type);
72247865 case ZigTypeIdUnion:
72257866 return resolve_llvm_types_union(g, type, wanted_resolve_status);
72267867 case ZigTypeIdPointer:
7227 return resolve_llvm_types_pointer(g, type);
7228 case ZigTypeIdPromise: {
7229 if (type->llvm_di_type != nullptr) return;
7230 ZigType *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
7231 type->llvm_type = get_llvm_type(g, u8_ptr_type);
7232 type->llvm_di_type = get_llvm_di_type(g, u8_ptr_type);
7233 return;
7234 }
7868 return resolve_llvm_types_pointer(g, type, wanted_resolve_status);
72357869 case ZigTypeIdInt:
72367870 return resolve_llvm_types_integer(g, type);
72377871 case ZigTypeIdOptional:
......@@ -7241,7 +7875,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72417875 case ZigTypeIdArray:
72427876 return resolve_llvm_types_array(g, type);
72437877 case ZigTypeIdFn:
7244 return resolve_llvm_types_fn(g, type);
7878 return resolve_llvm_types_fn_type(g, type);
72457879 case ZigTypeIdErrorSet: {
72467880 if (type->llvm_di_type != nullptr) return;
72477881
......@@ -7260,14 +7894,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
72607894 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);
72617895 return;
72627896 }
7897 case ZigTypeIdFnFrame:
7898 return resolve_llvm_types_async_frame(g, type, wanted_resolve_status);
7899 case ZigTypeIdAnyFrame:
7900 return resolve_llvm_types_any_frame(g, type, wanted_resolve_status);
72637901 }
72647902 zig_unreachable();
72657903}
72667904
72677905LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {
72687906 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));
7269 assert(type->abi_size == 0 || type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
7270 assert(type->abi_align == 0 || type->abi_align == LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
7907 assert(type->abi_size == 0 || type->abi_size >= LLVMABISizeOfType(g->target_data_ref, type->llvm_type));
7908 assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
72717909 return type->llvm_type;
72727910}
72737911
src/analyze.hpp+8-10
......@@ -11,11 +11,12 @@
1111#include "all_types.hpp"
1212
1313void semantic_analyze(CodeGen *g);
14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
14ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg);
1515ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg);
1717void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
1818ZigType *new_type_table_entry(ZigTypeId id);
19ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
1920ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
2021ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
2122 bool is_volatile, PtrLen ptr_len,
......@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
3738ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
3839ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
3940ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
40ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
41 ZigType *field_types[], size_t field_count);
42ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
43ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type);
4441ZigType *get_test_fn_type(CodeGen *g);
42ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
4543bool handle_is_ptr(ZigType *type_entry);
4644
4745bool type_has_bits(ZigType *type_entry);
......@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
106104void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);
107105
108106void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
109void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node);
110107
111108ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
112109ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
......@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
117114ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
118115ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
119116Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
120Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
121117Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
122118
123119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
......@@ -199,12 +195,11 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global
199195
200196
201197ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
202ZigType *get_ptr_to_stack_trace_type(CodeGen *g);
198ZigType *get_stack_trace_type(CodeGen *g);
203199bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);
204200
205201ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);
206202
207uint32_t get_coro_frame_align_bytes(CodeGen *g);
208203bool fn_type_can_fail(FnTypeId *fn_type_id);
209204bool type_can_fail(ZigType *type_entry);
210205bool fn_eval_cacheable(Scope *scope, ZigType *return_type);
......@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);
251246bool is_container(ZigType *type_entry);
252247ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);
253248
249void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
250bool fn_is_async(ZigFn *fn);
251
254252#endif
src/ast_render.cpp+19-26
......@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {
249249 return "IfOptional";
250250 case NodeTypeErrorSetDecl:
251251 return "ErrorSetDecl";
252 case NodeTypeCancel:
253 return "Cancel";
254252 case NodeTypeResume:
255253 return "Resume";
256254 case NodeTypeAwaitExpr:
257255 return "AwaitExpr";
258256 case NodeTypeSuspend:
259257 return "Suspend";
260 case NodeTypePromiseType:
261 return "PromiseType";
262258 case NodeTypePointerType:
263259 return "PointerType";
260 case NodeTypeAnyFrameType:
261 return "AnyFrameType";
264262 case NodeTypeEnumLiteral:
265263 return "EnumLiteral";
266264 }
......@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
699697 fprintf(ar->f, "@");
700698 }
701699 if (node->data.fn_call_expr.is_async) {
702 fprintf(ar->f, "async");
703 if (node->data.fn_call_expr.async_allocator != nullptr) {
704 fprintf(ar->f, "<");
705 render_node_extra(ar, node->data.fn_call_expr.async_allocator, true);
706 fprintf(ar->f, ">");
707 }
708 fprintf(ar->f, " ");
700 fprintf(ar->f, "async ");
709701 }
710702 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
711703 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);
......@@ -862,15 +854,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
862854 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);
863855 break;
864856 }
865 case NodeTypePromiseType:
866 {
867 fprintf(ar->f, "promise");
868 if (node->data.promise_type.payload_type != nullptr) {
869 fprintf(ar->f, "->");
870 render_node_grouped(ar, node->data.promise_type.payload_type);
871 }
872 break;
857 case NodeTypeAnyFrameType: {
858 fprintf(ar->f, "anyframe");
859 if (node->data.anyframe_type.payload_type != nullptr) {
860 fprintf(ar->f, "->");
861 render_node_grouped(ar, node->data.anyframe_type.payload_type);
873862 }
863 break;
864 }
874865 case NodeTypeErrorType:
875866 fprintf(ar->f, "anyerror");
876867 break;
......@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
11431134 fprintf(ar->f, "}");
11441135 break;
11451136 }
1146 case NodeTypeCancel:
1147 {
1148 fprintf(ar->f, "cancel ");
1149 render_node_grouped(ar, node->data.cancel_expr.expr);
1150 break;
1151 }
11521137 case NodeTypeResume:
11531138 {
11541139 fprintf(ar->f, "resume ");
......@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
11631148 }
11641149 case NodeTypeSuspend:
11651150 {
1166 fprintf(ar->f, "suspend");
11671151 if (node->data.suspend.block != nullptr) {
1152 fprintf(ar->f, "suspend ");
11681153 render_node_grouped(ar, node->data.suspend.block);
1154 } else {
1155 fprintf(ar->f, "suspend\n");
11691156 }
11701157 break;
11711158 }
......@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {
11911178
11921179 render_node_grouped(&ar, node);
11931180}
1181
1182void AstNode::src() {
1183 fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize "\n",
1184 buf_ptr(this->owner->data.structure.root_struct->path),
1185 this->line + 1, this->column + 1);
1186}
src/codegen.cpp+1248-943
......@@ -24,6 +24,12 @@
2424#include <stdio.h>
2525#include <errno.h>
2626
27enum ResumeId {
28 ResumeIdManual,
29 ResumeIdReturn,
30 ResumeIdCall,
31};
32
2733static void init_darwin_native(CodeGen *g) {
2834 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
2935 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
......@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
297303 zig_unreachable();
298304}
299305
306// label (grep this): [fn_frame_struct_layout]
307static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) {
308 // [0] *ReturnType (callee's)
309 // [1] *ReturnType (awaiter's)
310 // [2] ReturnType
311 uint32_t return_field_count = type_has_bits(return_type) ? 3 : 0;
312 return frame_ret_start + return_field_count;
313}
314
315// label (grep this): [fn_frame_struct_layout]
316static uint32_t frame_index_arg(CodeGen *g, ZigType *return_type) {
317 bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, return_type);
318 // [0] *StackTrace (callee's)
319 // [1] *StackTrace (awaiter's)
320 uint32_t trace_field_count = have_stack_trace ? 2 : 0;
321 return frame_index_trace_arg(g, return_type) + trace_field_count;
322}
323
324// label (grep this): [fn_frame_struct_layout]
325static uint32_t frame_index_trace_stack(CodeGen *g, FnTypeId *fn_type_id) {
326 uint32_t result = frame_index_arg(g, fn_type_id->return_type);
327 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
328 if (type_has_bits(fn_type_id->param_info->type)) {
329 result += 1;
330 }
331 }
332 return result;
333}
334
335
300336static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
301337 if (!g->have_err_ret_tracing) {
302338 return UINT32_MAX;
303339 }
304 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
305 return 0;
340 if (fn_is_async(fn_table_entry)) {
341 return UINT32_MAX;
306342 }
307343 ZigType *fn_type = fn_table_entry->type_entry;
308344 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
......@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {
343379 zig_unreachable();
344380}
345381
346static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
347 if (fn_table_entry->llvm_value)
348 return fn_table_entry->llvm_value;
382static bool codegen_have_frame_pointer(CodeGen *g) {
383 return g->build_mode == BuildModeDebug;
384}
349385
350 Buf *unmangled_name = &fn_table_entry->symbol_name;
386static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
387 Buf *unmangled_name = &fn->symbol_name;
351388 Buf *symbol_name;
352389 GlobalLinkageId linkage;
353 if (fn_table_entry->body_node == nullptr) {
390 if (fn->body_node == nullptr) {
354391 symbol_name = unmangled_name;
355392 linkage = GlobalLinkageIdStrong;
356 } else if (fn_table_entry->export_list.length == 0) {
393 } else if (fn->export_list.length == 0) {
357394 symbol_name = get_mangled_name(g, unmangled_name, false);
358395 linkage = GlobalLinkageIdInternal;
359396 } else {
360 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
397 GlobalExport *fn_export = &fn->export_list.items[0];
361398 symbol_name = &fn_export->name;
362399 linkage = fn_export->linkage;
363400 }
364401
365402 bool external_linkage = linkage != GlobalLinkageIdInternal;
366 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
403 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
367404 if (cc == CallingConventionStdcall && external_linkage &&
368405 g->zig_target->arch == ZigLLVM_x86)
369406 {
......@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371408 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372409 }
373410
411 bool is_async = fn_is_async(fn);
374412
375 ZigType *fn_type = fn_table_entry->type_entry;
413
414 ZigType *fn_type = fn->type_entry;
376415 // Make the raw_type_ref populated
377 (void)get_llvm_type(g, fn_type);
378 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
379 if (fn_table_entry->body_node == nullptr) {
416 resolve_llvm_types_fn(g, fn);
417 LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
418 LLVMValueRef llvm_fn = nullptr;
419 if (fn->body_node == nullptr) {
380420 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
381421 if (existing_llvm_fn) {
382 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
383 return fn_table_entry->llvm_value;
422 return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
384423 } else {
385424 auto entry = g->exported_symbol_names.maybe_get(symbol_name);
386425 if (entry == nullptr) {
387 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
426 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
388427
389428 if (target_is_wasm(g->zig_target)) {
390 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
391 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
429 assert(fn->proto_node->type == NodeTypeFnProto);
430 AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
392431 if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {
393 addLLVMFnAttrStr(fn_table_entry->llvm_value, "wasm-import-module", buf_ptr(fn_proto->lib_name));
432 addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name));
394433 }
395434 }
396435 } else {
397436 assert(entry->value->id == TldIdFn);
398437 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
399438 // Make the raw_type_ref populated
400 (void)get_llvm_type(g, tld_fn->fn_entry->type_entry);
439 resolve_llvm_types_fn(g, tld_fn->fn_entry);
401440 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
402 tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);
403 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
404 LLVMPointerType(fn_llvm_type, 0));
405 return fn_table_entry->llvm_value;
441 tld_fn->fn_entry->raw_type_ref);
442 llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0));
443 return llvm_fn;
406444 }
407445 }
408446 } else {
409 if (fn_table_entry->llvm_value == nullptr) {
410 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
447 if (llvm_fn == nullptr) {
448 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
411449 }
412450
413 for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {
414 GlobalExport *fn_export = &fn_table_entry->export_list.items[i];
415 LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value),
416 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
451 for (size_t i = 1; i < fn->export_list.length; i += 1) {
452 GlobalExport *fn_export = &fn->export_list.items[i];
453 LLVMAddAlias(g->module, LLVMTypeOf(llvm_fn), llvm_fn, buf_ptr(&fn_export->name));
417454 }
418455 }
419 fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
420456
421 switch (fn_table_entry->fn_inline) {
457 switch (fn->fn_inline) {
422458 case FnInlineAlways:
423 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");
424 g->inline_fns.append(fn_table_entry);
459 addLLVMFnAttr(llvm_fn, "alwaysinline");
460 g->inline_fns.append(fn);
425461 break;
426462 case FnInlineNever:
427 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
463 addLLVMFnAttr(llvm_fn, "noinline");
428464 break;
429465 case FnInlineAuto:
430 if (fn_table_entry->alignstack_value != 0) {
431 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
466 if (fn->alignstack_value != 0) {
467 addLLVMFnAttr(llvm_fn, "noinline");
432468 }
433469 break;
434470 }
435471
436472 if (cc == CallingConventionNaked) {
437 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
473 addLLVMFnAttr(llvm_fn, "naked");
438474 } else {
439 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
440 }
441 if (cc == CallingConventionAsync) {
442 addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
443 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
475 LLVMSetFunctionCallConv(llvm_fn, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
444476 }
445477
446 bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;
478 bool want_cold = fn->is_cold || cc == CallingConventionCold;
447479 if (want_cold) {
448 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
480 ZigLLVMAddFunctionAttrCold(llvm_fn);
449481 }
450482
451483
452 LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage));
484 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
453485
454486 if (linkage == GlobalLinkageIdInternal) {
455 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
487 LLVMSetUnnamedAddr(llvm_fn, true);
456488 }
457489
458490 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
459491 if (return_type->id == ZigTypeIdUnreachable) {
460 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
492 addLLVMFnAttr(llvm_fn, "noreturn");
461493 }
462494
463 if (fn_table_entry->body_node != nullptr) {
464 maybe_export_dll(g, fn_table_entry->llvm_value, linkage);
495 if (fn->body_node != nullptr) {
496 maybe_export_dll(g, llvm_fn, linkage);
465497
466498 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
467499 g->build_mode != BuildModeSmallRelease &&
468 !fn_table_entry->def_scope->safety_off;
500 !fn->def_scope->safety_off;
469501 if (want_fn_safety) {
470502 if (g->libc_link_lib != nullptr) {
471 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
472 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
503 addLLVMFnAttr(llvm_fn, "sspstrong");
504 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
473505 }
474506 }
475 if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) {
476 addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack");
507 if (g->have_stack_probing && !fn->def_scope->safety_off) {
508 addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack");
477509 }
478510 } else {
479 maybe_import_dll(g, fn_table_entry->llvm_value, linkage);
511 maybe_import_dll(g, llvm_fn, linkage);
480512 }
481513
482 if (fn_table_entry->alignstack_value != 0) {
483 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value);
514 if (fn->alignstack_value != 0) {
515 addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value);
484516 }
485517
486 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");
487 add_uwtable_attr(g, fn_table_entry->llvm_value);
488 addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");
489 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {
490 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
491 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
518 addLLVMFnAttr(llvm_fn, "nounwind");
519 add_uwtable_attr(g, llvm_fn);
520 addLLVMFnAttr(llvm_fn, "nobuiltin");
521 if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) {
522 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim", "true");
523 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim-non-leaf", nullptr);
492524 }
493 if (fn_table_entry->section_name) {
494 LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));
525 if (fn->section_name) {
526 LLVMSetSection(llvm_fn, buf_ptr(fn->section_name));
495527 }
496 if (fn_table_entry->align_bytes > 0) {
497 LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);
528 if (fn->align_bytes > 0) {
529 LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes);
498530 } else {
499531 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
500532 // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
......@@ -502,36 +534,50 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
502534 // use the ABI alignment, which is fine.
503535 }
504536
505 unsigned init_gen_i = 0;
506 if (!type_has_bits(return_type)) {
507 // nothing to do
508 } else if (type_is_nonnull_ptr(return_type)) {
509 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
510 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
511 // Sret pointers must not be address 0
512 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
513 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
514 if (cc_want_sret_attr(cc)) {
515 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
537 if (is_async) {
538 addLLVMArgAttr(llvm_fn, 0, "nonnull");
539 } else {
540 unsigned init_gen_i = 0;
541 if (!type_has_bits(return_type)) {
542 // nothing to do
543 } else if (type_is_nonnull_ptr(return_type)) {
544 addLLVMAttr(llvm_fn, 0, "nonnull");
545 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
546 // Sret pointers must not be address 0
547 addLLVMArgAttr(llvm_fn, 0, "nonnull");
548 addLLVMArgAttr(llvm_fn, 0, "sret");
549 if (cc_want_sret_attr(cc)) {
550 addLLVMArgAttr(llvm_fn, 0, "noalias");
551 }
552 init_gen_i = 1;
516553 }
517 init_gen_i = 1;
518 }
519554
520 // set parameter attributes
521 FnWalk fn_walk = {};
522 fn_walk.id = FnWalkIdAttrs;
523 fn_walk.data.attrs.fn = fn_table_entry;
524 fn_walk.data.attrs.gen_i = init_gen_i;
525 walk_function_params(g, fn_type, &fn_walk);
555 // set parameter attributes
556 FnWalk fn_walk = {};
557 fn_walk.id = FnWalkIdAttrs;
558 fn_walk.data.attrs.fn = fn;
559 fn_walk.data.attrs.llvm_fn = llvm_fn;
560 fn_walk.data.attrs.gen_i = init_gen_i;
561 walk_function_params(g, fn_type, &fn_walk);
526562
527 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
528 if (err_ret_trace_arg_index != UINT32_MAX) {
529 // Error return trace memory is in the stack, which is impossible to be at address 0
530 // on any architecture.
531 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
563 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn);
564 if (err_ret_trace_arg_index != UINT32_MAX) {
565 // Error return trace memory is in the stack, which is impossible to be at address 0
566 // on any architecture.
567 addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull");
568 }
532569 }
533570
534 return fn_table_entry->llvm_value;
571 return llvm_fn;
572}
573
574static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) {
575 if (fn->llvm_value)
576 return fn->llvm_value;
577
578 fn->llvm_value = make_fn_llvm_value(g, fn);
579 fn->llvm_name = strdup(LLVMGetValueName(fn->llvm_value));
580 return fn->llvm_value;
535581}
536582
537583static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
......@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
559605 unsigned flags = ZigLLVM_DIFlags_StaticMember;
560606 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);
561607 assert(fn_di_scope != nullptr);
608 assert(fn_table_entry->raw_di_type != nullptr);
562609 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
563610 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
564611 import->data.structure.root_struct->di_file, line_number,
565 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,
612 fn_table_entry->raw_di_type, is_internal_linkage,
566613 is_definition, scope_line, flags, is_optimized, nullptr);
567614
568615 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
......@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
597644 case ScopeIdLoop:
598645 case ScopeIdSuspend:
599646 case ScopeIdCompTime:
600 case ScopeIdCoroPrelude:
601647 case ScopeIdRuntime:
602648 return get_di_scope(g, scope->parent);
603649 }
......@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
798844 return false;
799845}
800846
801static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
847static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) {
802848 // TODO memoize
803 Scope *scope = instruction->scope;
804849 while (scope) {
805850 if (scope->id == ScopeIdBlock) {
806851 ScopeBlock *block_scope = (ScopeBlock *)scope;
......@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
818863 g->build_mode != BuildModeSmallRelease);
819864}
820865
866static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
867 return ir_want_runtime_safety_scope(g, instruction->scope);
868}
869
821870static Buf *panic_msg_buf(PanicMsgId msg_id) {
822871 switch (msg_id) {
823872 case PanicMsgIdCount:
......@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
858907 return buf_create_from_str("integer part of floating point value out of bounds");
859908 case PanicMsgIdPtrCastNull:
860909 return buf_create_from_str("cast causes pointer to be null");
910 case PanicMsgIdBadResume:
911 return buf_create_from_str("resumed an async function which already returned");
912 case PanicMsgIdBadAwait:
913 return buf_create_from_str("async function awaited twice");
914 case PanicMsgIdBadReturn:
915 return buf_create_from_str("async function returned twice");
916 case PanicMsgIdResumedAnAwaitingFn:
917 return buf_create_from_str("awaiting function resumed");
918 case PanicMsgIdFrameTooSmall:
919 return buf_create_from_str("frame too small");
920 case PanicMsgIdResumedFnPendingAwait:
921 return buf_create_from_str("resumed an async function which can only be awaited");
861922 }
862923 zig_unreachable();
863924}
......@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
882943 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));
883944}
884945
946static ZigType *ptr_to_stack_trace_type(CodeGen *g) {
947 return get_pointer_to_type(g, get_stack_trace_type(g), false);
948}
949
885950static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
886951 assert(g->panic_fn != nullptr);
887952 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
888953 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
889954 if (stack_trace_arg == nullptr) {
890 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
891 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
955 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
892956 }
893957 LLVMValueRef args[] = {
894958 msg_arg,
......@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
904968 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
905969}
906970
907static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
908 if (ir_want_runtime_safety(g, source_instruction)) {
971static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) {
972 if (ir_want_runtime_safety_scope(g, source_scope)) {
909973 gen_safety_crash(g, msg_id);
910974 } else {
911975 LLVMBuildUnreachable(g->builder);
912976 }
913977}
914978
979static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
980 return gen_assertion_scope(g, msg_id, source_instruction->scope);
981}
982
915983static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
916984 if (g->stacksave_fn_val)
917985 return g->stacksave_fn_val;
......@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
9591027 return g->write_register_fn_val;
9601028}
9611029
962static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
963 if (g->coro_destroy_fn_val)
964 return g->coro_destroy_fn_val;
965
966 LLVMTypeRef param_types[] = {
967 LLVMPointerType(LLVMInt8Type(), 0),
968 };
969 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
970 Buf *name = buf_sprintf("llvm.coro.destroy");
971 g->coro_destroy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
972 assert(LLVMGetIntrinsicID(g->coro_destroy_fn_val));
973
974 return g->coro_destroy_fn_val;
975}
976
977static LLVMValueRef get_coro_id_fn_val(CodeGen *g) {
978 if (g->coro_id_fn_val)
979 return g->coro_id_fn_val;
980
981 LLVMTypeRef param_types[] = {
982 LLVMInt32Type(),
983 LLVMPointerType(LLVMInt8Type(), 0),
984 LLVMPointerType(LLVMInt8Type(), 0),
985 LLVMPointerType(LLVMInt8Type(), 0),
986 };
987 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 4, false);
988 Buf *name = buf_sprintf("llvm.coro.id");
989 g->coro_id_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
990 assert(LLVMGetIntrinsicID(g->coro_id_fn_val));
991
992 return g->coro_id_fn_val;
993}
994
995static LLVMValueRef get_coro_alloc_fn_val(CodeGen *g) {
996 if (g->coro_alloc_fn_val)
997 return g->coro_alloc_fn_val;
998
999 LLVMTypeRef param_types[] = {
1000 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1001 };
1002 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 1, false);
1003 Buf *name = buf_sprintf("llvm.coro.alloc");
1004 g->coro_alloc_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1005 assert(LLVMGetIntrinsicID(g->coro_alloc_fn_val));
1006
1007 return g->coro_alloc_fn_val;
1008}
1009
1010static LLVMValueRef get_coro_size_fn_val(CodeGen *g) {
1011 if (g->coro_size_fn_val)
1012 return g->coro_size_fn_val;
1013
1014 LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->llvm_type, nullptr, 0, false);
1015 Buf *name = buf_sprintf("llvm.coro.size.i%d", g->pointer_size_bytes * 8);
1016 g->coro_size_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1017 assert(LLVMGetIntrinsicID(g->coro_size_fn_val));
1018
1019 return g->coro_size_fn_val;
1020}
1021
1022static LLVMValueRef get_coro_begin_fn_val(CodeGen *g) {
1023 if (g->coro_begin_fn_val)
1024 return g->coro_begin_fn_val;
1025
1026 LLVMTypeRef param_types[] = {
1027 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1028 LLVMPointerType(LLVMInt8Type(), 0),
1029 };
1030 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1031 Buf *name = buf_sprintf("llvm.coro.begin");
1032 g->coro_begin_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1033 assert(LLVMGetIntrinsicID(g->coro_begin_fn_val));
1034
1035 return g->coro_begin_fn_val;
1036}
1037
1038static LLVMValueRef get_coro_suspend_fn_val(CodeGen *g) {
1039 if (g->coro_suspend_fn_val)
1040 return g->coro_suspend_fn_val;
1041
1042 LLVMTypeRef param_types[] = {
1043 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1044 LLVMInt1Type(),
1045 };
1046 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt8Type(), param_types, 2, false);
1047 Buf *name = buf_sprintf("llvm.coro.suspend");
1048 g->coro_suspend_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1049 assert(LLVMGetIntrinsicID(g->coro_suspend_fn_val));
1050
1051 return g->coro_suspend_fn_val;
1052}
1053
1054static LLVMValueRef get_coro_end_fn_val(CodeGen *g) {
1055 if (g->coro_end_fn_val)
1056 return g->coro_end_fn_val;
1057
1058 LLVMTypeRef param_types[] = {
1059 LLVMPointerType(LLVMInt8Type(), 0),
1060 LLVMInt1Type(),
1061 };
1062 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 2, false);
1063 Buf *name = buf_sprintf("llvm.coro.end");
1064 g->coro_end_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1065 assert(LLVMGetIntrinsicID(g->coro_end_fn_val));
1066
1067 return g->coro_end_fn_val;
1068}
1069
1070static LLVMValueRef get_coro_free_fn_val(CodeGen *g) {
1071 if (g->coro_free_fn_val)
1072 return g->coro_free_fn_val;
1073
1074 LLVMTypeRef param_types[] = {
1075 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1076 LLVMPointerType(LLVMInt8Type(), 0),
1077 };
1078 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1079 Buf *name = buf_sprintf("llvm.coro.free");
1080 g->coro_free_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1081 assert(LLVMGetIntrinsicID(g->coro_free_fn_val));
1082
1083 return g->coro_free_fn_val;
1084}
1085
1086static LLVMValueRef get_coro_resume_fn_val(CodeGen *g) {
1087 if (g->coro_resume_fn_val)
1088 return g->coro_resume_fn_val;
1089
1090 LLVMTypeRef param_types[] = {
1091 LLVMPointerType(LLVMInt8Type(), 0),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
1094 Buf *name = buf_sprintf("llvm.coro.resume");
1095 g->coro_resume_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_resume_fn_val));
1097
1098 return g->coro_resume_fn_val;
1099}
1100
1101static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
1102 if (g->coro_save_fn_val)
1103 return g->coro_save_fn_val;
1104
1105 LLVMTypeRef param_types[] = {
1106 LLVMPointerType(LLVMInt8Type(), 0),
1107 };
1108 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 1, false);
1109 Buf *name = buf_sprintf("llvm.coro.save");
1110 g->coro_save_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1111 assert(LLVMGetIntrinsicID(g->coro_save_fn_val));
1112
1113 return g->coro_save_fn_val;
1114}
1115
1116static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1117 if (g->coro_promise_fn_val)
1118 return g->coro_promise_fn_val;
1119
1120 LLVMTypeRef param_types[] = {
1121 LLVMPointerType(LLVMInt8Type(), 0),
1122 LLVMInt32Type(),
1123 LLVMInt1Type(),
1124 };
1125 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1126 Buf *name = buf_sprintf("llvm.coro.promise");
1127 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1128 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1129
1130 return g->coro_promise_fn_val;
1131}
1132
11331030static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
11341031 if (g->return_address_fn_val)
11351032 return g->return_address_fn_val;
......@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
11491046 return g->add_error_return_trace_addr_fn_val;
11501047
11511048 LLVMTypeRef arg_types[] = {
1152 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1049 get_llvm_type(g, ptr_to_stack_trace_type(g)),
11531050 g->builtin_types.entry_usize->llvm_type,
11541051 };
11551052 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
......@@ -1164,7 +1061,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
11641061 // Error return trace memory is in the stack, which is impossible to be at address 0
11651062 // on any architecture.
11661063 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1167 if (g->build_mode == BuildModeDebug) {
1064 if (codegen_have_frame_pointer(g)) {
11681065 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
11691066 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
11701067 }
......@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
12221119 return fn_val;
12231120}
12241121
1225static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1226 if (g->merge_err_ret_traces_fn_val)
1227 return g->merge_err_ret_traces_fn_val;
1228
1229 assert(g->stack_trace_type != nullptr);
1230
1231 LLVMTypeRef param_types[] = {
1232 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1233 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1234 };
1235 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1236
1237 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1238 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1239 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1240 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1241 addLLVMFnAttr(fn_val, "nounwind");
1242 add_uwtable_attr(g, fn_val);
1243 // Error return trace memory is in the stack, which is impossible to be at address 0
1244 // on any architecture.
1245 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1246 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1247 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1248 // Error return trace memory is in the stack, which is impossible to be at address 0
1249 // on any architecture.
1250 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1251 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1252 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1253 if (g->build_mode == BuildModeDebug) {
1254 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1255 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1256 }
1257
1258 // this is above the ZigLLVMClearCurrentDebugLocation
1259 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1260
1261 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1262 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1263 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1264 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1265 ZigLLVMClearCurrentDebugLocation(g->builder);
1266
1267 // var frame_index: usize = undefined;
1268 // var frames_left: usize = undefined;
1269 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1270 // frame_index = 0;
1271 // frames_left = src_stack_trace.index;
1272 // if (frames_left == 0) return;
1273 // } else {
1274 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1275 // frames_left = src_stack_trace.instruction_addresses.len;
1276 // }
1277 // while (true) {
1278 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1279 // frames_left -= 1;
1280 // if (frames_left == 0) return;
1281 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1282 // }
1283 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1284
1285 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
1286 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
1287
1288 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1289 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1290
1291 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1292 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1293 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1294 (unsigned)src_index_field_index, "");
1295 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1296 (unsigned)src_addresses_field_index, "");
1297 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1298 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1299 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1300 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1301 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1302 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1303 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1304 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1305 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1306 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1307 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1308 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1309 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1310
1311 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1312 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
1313 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1314 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1315 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1316 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1317
1318 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1319 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
1320 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1321 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1322 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1323 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1324 LLVMBuildBr(g->builder, loop_block);
1325
1326 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1327 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1328 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1329 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1330 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1331 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1332 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1333 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1334 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1335 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1336 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1337
1338 LLVMPositionBuilderAtEnd(g->builder, return_block);
1339 LLVMBuildRetVoid(g->builder);
1340
1341 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1342 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1343 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1344 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1345 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1346 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1347 LLVMBuildBr(g->builder, loop_block);
1348
1349 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1350 if (!g->strip_debug_symbols) {
1351 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1352 }
1353
1354 g->merge_err_ret_traces_fn_val = fn_val;
1355 return fn_val;
1356
1357}
1358
13591122static LLVMValueRef get_return_err_fn(CodeGen *g) {
13601123 if (g->return_err_fn != nullptr)
13611124 return g->return_err_fn;
......@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13641127
13651128 LLVMTypeRef arg_types[] = {
13661129 // error return trace pointer
1367 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1130 get_llvm_type(g, ptr_to_stack_trace_type(g)),
13681131 };
13691132 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
13701133
......@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13761139 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
13771140 addLLVMFnAttr(fn_val, "nounwind");
13781141 add_uwtable_attr(g, fn_val);
1379 // Error return trace memory is in the stack, which is impossible to be at address 0
1380 // on any architecture.
1381 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1382 if (g->build_mode == BuildModeDebug) {
1142 if (codegen_have_frame_pointer(g)) {
13831143 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
13841144 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
13851145 }
......@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
14001160 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
14011161 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
14021162
1163 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1164 LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull");
1165
1166 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_ret_trace_ptr,
1167 LLVMConstNull(LLVMTypeOf(err_ret_trace_ptr)), "");
1168 LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block);
1169
1170 LLVMPositionBuilderAtEnd(g->builder, return_block);
1171 LLVMBuildRetVoid(g->builder);
1172
1173 LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block);
14031174 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
14041175 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
14051176 LLVMBuildRetVoid(g->builder);
......@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
14341205 LLVMTypeRef fn_type_ref;
14351206 if (g->have_err_ret_tracing) {
14361207 LLVMTypeRef arg_types[] = {
1437 get_llvm_type(g, g->ptr_to_stack_trace_type),
1208 get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)),
14381209 get_llvm_type(g, g->err_tag_type),
14391210 };
14401211 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
......@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
14511222 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
14521223 addLLVMFnAttr(fn_val, "nounwind");
14531224 add_uwtable_attr(g, fn_val);
1454 if (g->build_mode == BuildModeDebug) {
1225 if (codegen_have_frame_pointer(g)) {
14551226 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
14561227 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
14571228 }
......@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
15431314 return fn_val;
15441315}
15451316
1546static bool is_coro_prelude_scope(Scope *scope) {
1547 while (scope != nullptr) {
1548 if (scope->id == ScopeIdCoroPrelude) {
1549 return true;
1550 } else if (scope->id == ScopeIdFnDef) {
1551 break;
1552 }
1553 scope = scope->parent;
1554 }
1555 return false;
1556}
1557
15581317static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
15591318 if (!g->have_err_ret_tracing) {
15601319 return nullptr;
15611320 }
1562 if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
1563 return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack;
1564 }
15651321 if (g->cur_err_ret_trace_val_stack != nullptr) {
15661322 return g->cur_err_ret_trace_val_stack;
15671323 }
......@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
15741330 if (g->have_err_ret_tracing) {
15751331 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
15761332 if (err_ret_trace_val == nullptr) {
1577 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1578 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
1333 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
15791334 }
15801335 LLVMValueRef args[] = {
15811336 err_ret_trace_val,
......@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
18201575 }
18211576}
18221577
1823static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
1578static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
18241579 LLVMValueRef value)
18251580{
18261581 assert(ptr_type->id == ZigTypeIdPointer);
18271582 ZigType *child_type = ptr_type->data.pointer.child_type;
18281583
18291584 if (!type_has_bits(child_type))
1830 return nullptr;
1585 return;
18311586
18321587 if (handle_is_ptr(child_type)) {
18331588 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);
......@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18471602 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,
18481603 LLVMConstInt(usize->llvm_type, size_bytes, false),
18491604 ptr_type->data.pointer.is_volatile);
1850 return nullptr;
1605 return;
18511606 }
18521607
18531608 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
18541609 if (host_int_bytes == 0) {
18551610 gen_store(g, value, ptr, ptr_type);
1856 return nullptr;
1611 return;
18571612 }
18581613
18591614 bool big_endian = g->is_big_endian;
......@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18831638 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
18841639
18851640 gen_store(g, ored_value, ptr, ptr_type);
1886 return nullptr;
1641 return;
18871642}
18881643
18891644static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
......@@ -1967,7 +1722,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
19671722 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
19681723 ty = param_info->type;
19691724 source_node = fn_walk->data.attrs.fn->proto_node;
1970 llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1725 llvm_fn = fn_walk->data.attrs.llvm_fn;
19711726 break;
19721727 case FnWalkIdCall: {
19731728 if (src_i >= fn_walk->data.call.inst->arg_count)
......@@ -2149,10 +1904,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
21491904 }
21501905 case FnWalkIdInits: {
21511906 clear_debug_source_node(g);
2152 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2153 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2154 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2155 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1907 if (!fn_is_async(fn_walk->data.inits.fn)) {
1908 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
1909 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
1910 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
1911 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1912 }
21561913 if (var->decl_node) {
21571914 gen_var_debug_decl(g, var);
21581915 }
......@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22011958 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
22021959 assert(param_value);
22031960 fn_walk->data.call.gen_param_values->append(param_value);
1961 fn_walk->data.call.gen_param_types->append(param_type);
22041962 }
22051963 }
22061964 return;
......@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22161974
22171975 switch (fn_walk->id) {
22181976 case FnWalkIdAttrs: {
2219 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1977 LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn;
22201978 bool is_byval = gen_info->is_byval;
22211979 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
22221980
......@@ -2245,7 +2003,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22452003 assert(variable);
22462004 assert(variable->value_ref);
22472005
2248 if (!handle_is_ptr(variable->var_type)) {
2006 if (!handle_is_ptr(variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) {
22492007 clear_debug_source_node(g);
22502008 ZigType *fn_type = fn_table_entry->type_entry;
22512009 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;
......@@ -2271,48 +2029,357 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22712029 }
22722030}
22732031
2032static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
2033 if (g->merge_err_ret_traces_fn_val)
2034 return g->merge_err_ret_traces_fn_val;
2035
2036 assert(g->stack_trace_type != nullptr);
2037
2038 LLVMTypeRef param_types[] = {
2039 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2040 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2041 };
2042 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
2043
2044 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
2045 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
2046 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
2047 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
2048 addLLVMFnAttr(fn_val, "nounwind");
2049 add_uwtable_attr(g, fn_val);
2050 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
2051 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
2052
2053 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
2054 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
2055 if (g->build_mode == BuildModeDebug) {
2056 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
2057 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
2058 }
2059
2060 // this is above the ZigLLVMClearCurrentDebugLocation
2061 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
2062
2063 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
2064 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
2065 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
2066 LLVMPositionBuilderAtEnd(g->builder, entry_block);
2067 ZigLLVMClearCurrentDebugLocation(g->builder);
2068
2069 // if (dest_stack_trace == null or src_stack_trace == null) return;
2070 // var frame_index: usize = undefined;
2071 // var frames_left: usize = undefined;
2072 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
2073 // frame_index = 0;
2074 // frames_left = src_stack_trace.index;
2075 // if (frames_left == 0) return;
2076 // } else {
2077 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
2078 // frames_left = src_stack_trace.instruction_addresses.len;
2079 // }
2080 // while (true) {
2081 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
2082 // frames_left -= 1;
2083 // if (frames_left == 0) return;
2084 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
2085 // }
2086 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
2087 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull");
2088
2089 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
2090 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
2091
2092 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
2093 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
2094
2095 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr,
2096 LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), "");
2097 LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr,
2098 LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), "");
2099 LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, "");
2100 LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block);
2101
2102 LLVMPositionBuilderAtEnd(g->builder, non_null_block);
2103 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
2104 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
2105 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2106 (unsigned)src_index_field_index, "");
2107 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2108 (unsigned)src_addresses_field_index, "");
2109 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
2110 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
2111 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
2112 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
2113 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
2114 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
2115 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
2116 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
2117 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
2118 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
2119 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
2120 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
2121 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
2122
2123 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
2124 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
2125 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
2126 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
2127 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
2128 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
2129
2130 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
2131 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
2132 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
2133 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
2134 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
2135 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
2136 LLVMBuildBr(g->builder, loop_block);
2137
2138 LLVMPositionBuilderAtEnd(g->builder, loop_block);
2139 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2140 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
2141 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
2142 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
2143 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
2144 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
2145 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
2146 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
2147 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
2148 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
2149
2150 LLVMPositionBuilderAtEnd(g->builder, return_block);
2151 LLVMBuildRetVoid(g->builder);
2152
2153 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2154 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
2155 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2156 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
2157 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
2158 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
2159 LLVMBuildBr(g->builder, loop_block);
2160
2161 LLVMPositionBuilderAtEnd(g->builder, prev_block);
2162 if (!g->strip_debug_symbols) {
2163 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
2164 }
2165
2166 g->merge_err_ret_traces_fn_val = fn_val;
2167 return fn_val;
2168
2169}
22742170static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
22752171 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
22762172{
22772173 assert(g->have_err_ret_tracing);
22782174
22792175 LLVMValueRef return_err_fn = get_return_err_fn(g);
2280 LLVMValueRef args[] = {
2281 get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope),
2282 };
2283 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
2176 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2177 ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
22842178 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2285 return call_instruction;
2179
2180 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2181 if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
2182 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
2183 frame_index_trace_arg(g, ret_type), "");
2184 LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr);
2185 }
2186
2187 return nullptr;
2188}
2189
2190static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id,
2191 LLVMBasicBlockRef end_bb)
2192{
2193 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2194 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
2195 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
2196 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
2197 LLVMConstInt(usize_type_ref, resume_id, false));
2198 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, "");
2199 LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block);
2200
2201 LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
2202 gen_assertion(g, msg_id, source_instr);
2203
2204 LLVMPositionBuilderAtEnd(g->builder, end_bb);
2205}
2206
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 = LLVMConstSub(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;
22862228}
22872229
2288static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
2230static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) {
2231 LLVMSetTailCall(call_inst, true);
2232}
2233
2234static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMValueRef ptr, LLVMValueRef val,
2235 LLVMAtomicOrdering order)
2236{
2237 if (g->is_single_threaded) {
2238 LLVMValueRef loaded = LLVMBuildLoad(g->builder, ptr, "");
2239 LLVMValueRef modified;
2240 switch (op) {
2241 case LLVMAtomicRMWBinOpXchg:
2242 modified = val;
2243 break;
2244 case LLVMAtomicRMWBinOpXor:
2245 modified = LLVMBuildXor(g->builder, loaded, val, "");
2246 break;
2247 default:
2248 zig_unreachable();
2249 }
2250 LLVMBuildStore(g->builder, modified, ptr);
2251 return loaded;
2252 } else {
2253 return LLVMBuildAtomicRMW(g->builder, op, ptr, val, order, false);
2254 }
2255}
2256
2257static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) {
2258 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2259
2260 ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value.type : nullptr;
2261 bool operand_has_bits = (operand_type != nullptr) && type_has_bits(operand_type);
2262 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2263 bool ret_type_has_bits = type_has_bits(ret_type);
2264
2265 if (operand_has_bits && instruction->operand != nullptr) {
2266 bool need_store = instruction->operand->value.special != ConstValSpecialRuntime || !handle_is_ptr(ret_type);
2267 if (need_store) {
2268 // It didn't get written to the result ptr. We do that now.
2269 ZigType *ret_ptr_type = get_pointer_to_type(g, ret_type, true);
2270 gen_assign_raw(g, g->cur_ret_ptr, ret_ptr_type, ir_llvm_value(g, instruction->operand));
2271 }
2272 }
2273
2274 // Whether we tail resume the awaiter, or do an early return, we are done and will not be resumed.
2275 if (ir_want_runtime_safety(g, &instruction->base)) {
2276 LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref);
2277 LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr);
2278 }
2279
2280 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
2281 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
2282
2283 LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXor, g->cur_async_awaiter_ptr,
2284 all_ones, LLVMAtomicOrderingAcquire);
2285
2286 LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn");
2287 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
2288 LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem");
2289
2290 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2);
2291
2292 LLVMAddCase(switch_instr, zero, early_return_block);
2293 LLVMAddCase(switch_instr, all_ones, bad_return_block);
2294
2295 // Something has gone horribly wrong, and this is an invalid second return.
2296 LLVMPositionBuilderAtEnd(g->builder, bad_return_block);
2297 gen_assertion(g, PanicMsgIdBadReturn, &instruction->base);
2298
2299 // There is no awaiter yet, but we're completely done.
2300 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
2301 LLVMBuildRetVoid(g->builder);
2302
2303 // We need to resume the caller by tail calling them,
2304 // but first write through the result pointer and possibly
2305 // error return trace pointer.
2306 LLVMPositionBuilderAtEnd(g->builder, resume_them_block);
2307
2308 if (ret_type_has_bits) {
2309 // If the awaiter result pointer is non-null, we need to copy the result to there.
2310 LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult");
2311 LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd");
2312 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start + 1, "");
2313 LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad(g->builder, awaiter_ret_ptr_ptr, "");
2314 LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr));
2315 LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, "");
2316 LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block);
2317
2318 LLVMPositionBuilderAtEnd(g->builder, copy_block);
2319 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
2320 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, "");
2321 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, "");
2322 bool is_volatile = false;
2323 uint32_t abi_align = get_abi_alignment(g, ret_type);
2324 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false);
2325 ZigLLVMBuildMemCpy(g->builder,
2326 dest_ptr_casted, abi_align,
2327 src_ptr_casted, abi_align, byte_count_val, is_volatile);
2328 LLVMBuildBr(g->builder, copy_end_block);
2329
2330 LLVMPositionBuilderAtEnd(g->builder, copy_end_block);
2331 if (codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
2332 LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
2333 frame_index_trace_arg(g, ret_type) + 1, "");
2334 LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, awaiter_trace_ptr_ptr, "");
2335 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
2336 LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val };
2337 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
2338 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2339 }
2340 }
2341
2342 // Resume the caller by tail calling them.
2343 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
2344 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val, get_llvm_type(g, any_frame_type), "");
2345 LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn);
2346 set_tail_call_if_appropriate(g, call_inst);
2347 LLVMBuildRetVoid(g->builder);
2348}
2349
2350static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *instruction) {
2351 if (fn_is_async(g->cur_fn)) {
2352 gen_async_return(g, instruction);
2353 return nullptr;
2354 }
2355
22892356 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
2290 if (return_instruction->value == nullptr) {
2357 if (instruction->operand == nullptr) {
22912358 LLVMBuildRetVoid(g->builder);
22922359 return nullptr;
22932360 }
22942361 assert(g->cur_ret_ptr);
2295 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,
2296 return_instruction->base.source_node);
2297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2298 ZigType *return_type = return_instruction->value->value.type;
2362 src_assert(instruction->operand->value.special != ConstValSpecialRuntime,
2363 instruction->base.source_node);
2364 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2365 ZigType *return_type = instruction->operand->value.type;
22992366 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
23002367 LLVMBuildRetVoid(g->builder);
23012368 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
23022369 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
23032370 {
2304 if (return_instruction->value == nullptr) {
2371 if (instruction->operand == nullptr) {
23052372 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
23062373 LLVMBuildRet(g->builder, by_val_value);
23072374 } else {
2308 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2375 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
23092376 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
23102377 LLVMBuildRet(g->builder, by_val_value);
23112378 }
2312 } else if (return_instruction->value == nullptr) {
2379 } else if (instruction->operand == nullptr) {
23132380 LLVMBuildRetVoid(g->builder);
23142381 } else {
2315 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
2382 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
23162383 LLVMBuildRet(g->builder, value);
23172384 }
23182385 return nullptr;
......@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
32423309 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
32433310}
32443311
3245static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
3246 ZigVar *var = instruction->var;
3247
3312static void render_decl_var(CodeGen *g, ZigVar *var) {
32483313 if (!type_has_bits(var->var_type))
3249 return nullptr;
3314 return;
32503315
3251 var->value_ref = ir_llvm_value(g, instruction->var_ptr);
3316 var->value_ref = ir_llvm_value(g, var->ptr_instruction);
32523317 gen_var_debug_decl(g, var);
3318}
3319
3320static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
3321 instruction->var->ptr_instruction = instruction->var_ptr;
3322 render_decl_var(g, instruction->var);
32533323 return nullptr;
32543324}
32553325
......@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
34673537static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,
34683538 IrInstructionReturnPtr *instruction)
34693539{
3470 src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type),
3471 instruction->base.source_node);
3540 if (!type_has_bits(instruction->base.value.type))
3541 return nullptr;
3542 src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node);
34723543 return g->cur_ret_ptr;
34733544}
34743545
......@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
35663637 }
35673638}
35683639
3569static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) {
3570 return g->have_err_ret_tracing &&
3571 (fn_type_id->return_type->id == ZigTypeIdErrorUnion ||
3572 fn_type_id->return_type->id == ZigTypeIdErrorSet ||
3573 fn_type_id->cc == CallingConventionAsync);
3574}
3575
3576static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3577 // 0 1 2 3
3578 // err_ret_stack allocator_ptr err_code other_args...
3579 return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0;
3580}
3581
3582static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3583 // 0 1 2 3
3584 // err_ret_stack allocator_ptr err_code other_args...
3585 return 1 + get_async_allocator_arg_index(g, fn_type_id);
3586}
3587
3588
35893640static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
35903641 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
35913642 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
......@@ -3623,16 +3674,124 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
36233674 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
36243675}
36253676
3677static void render_async_spills(CodeGen *g) {
3678 ZigType *fn_type = g->cur_fn->type_entry;
3679 ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base);
3680 uint32_t async_var_index = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3681 for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) {
3682 ZigVar *var = g->cur_fn->variable_list.at(var_i);
3683
3684 if (!type_has_bits(var->var_type)) {
3685 continue;
3686 }
3687 if (ir_get_var_is_comptime(var))
3688 continue;
3689 switch (type_requires_comptime(g, var->var_type)) {
3690 case ReqCompTimeInvalid:
3691 zig_unreachable();
3692 case ReqCompTimeYes:
3693 continue;
3694 case ReqCompTimeNo:
3695 break;
3696 }
3697 if (var->src_arg_index == SIZE_MAX) {
3698 continue;
3699 }
3700
3701 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index,
3702 buf_ptr(&var->name));
3703 async_var_index += 1;
3704 if (var->decl_node) {
3705 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
3706 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
3707 (unsigned)(var->decl_node->line + 1),
3708 get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
3709 gen_var_debug_decl(g, var);
3710 }
3711 }
3712
3713 ZigType *frame_type = g->cur_fn->frame_type->data.frame.locals_struct;
3714
3715 for (size_t alloca_i = 0; alloca_i < g->cur_fn->alloca_gen_list.length; alloca_i += 1) {
3716 IrInstructionAllocaGen *instruction = g->cur_fn->alloca_gen_list.at(alloca_i);
3717 if (instruction->field_index == SIZE_MAX)
3718 continue;
3719
3720 size_t gen_index = frame_type->data.structure.fields[instruction->field_index].gen_index;
3721 instruction->base.llvm_value = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, gen_index,
3722 instruction->name_hint);
3723 }
3724}
3725
3726static void render_async_var_decls(CodeGen *g, Scope *scope) {
3727 for (;;) {
3728 switch (scope->id) {
3729 case ScopeIdCImport:
3730 zig_unreachable();
3731 case ScopeIdFnDef:
3732 return;
3733 case ScopeIdVarDecl: {
3734 ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
3735 if (var->ptr_instruction != nullptr) {
3736 render_decl_var(g, var);
3737 }
3738 // fallthrough
3739 }
3740 case ScopeIdDecls:
3741 case ScopeIdBlock:
3742 case ScopeIdDefer:
3743 case ScopeIdDeferExpr:
3744 case ScopeIdLoop:
3745 case ScopeIdSuspend:
3746 case ScopeIdCompTime:
3747 case ScopeIdRuntime:
3748 scope = scope->parent;
3749 continue;
3750 }
3751 }
3752}
3753
3754static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
3755 LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
3756 LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
3757 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
3758 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
3759 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
3760 return LLVMBuildLoad(g->builder, prefix_ptr, "");
3761}
3762
3763static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
3764 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3765 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3766
3767 LLVMValueRef index_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 0, "");
3768 LLVMBuildStore(g->builder, zero, index_ptr);
3769
3770 LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 1, "");
3771 LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_ptr_index, "");
3772 LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) };
3773 LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP(g->builder, addrs_field_ptr, indices, 2, "");
3774 LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr);
3775
3776 LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_len_index, "");
3777 LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr);
3778}
3779
36263780static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3781 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3782
36273783 LLVMValueRef fn_val;
36283784 ZigType *fn_type;
3785 bool callee_is_async;
36293786 if (instruction->fn_entry) {
36303787 fn_val = fn_llvm_value(g, instruction->fn_entry);
36313788 fn_type = instruction->fn_entry->type_entry;
3789 callee_is_async = fn_is_async(instruction->fn_entry);
36323790 } else {
36333791 assert(instruction->fn_ref);
36343792 fn_val = ir_llvm_value(g, instruction->fn_ref);
36353793 fn_type = instruction->fn_ref->value.type;
3794 callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync;
36363795 }
36373796
36383797 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -3643,27 +3802,156 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36433802 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
36443803
36453804 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
3646 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
3805 bool prefix_arg_err_ret_stack = codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type);
36473806 bool is_var_args = fn_type_id->is_var_args;
36483807 ZigList<LLVMValueRef> gen_param_values = {};
3808 ZigList<ZigType *> gen_param_types = {};
36493809 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3650 if (first_arg_ret) {
3651 gen_param_values.append(result_loc);
3652 }
3653 if (prefix_arg_err_ret_stack) {
3654 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3655 }
3656 if (instruction->is_async) {
3657 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
3810 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3811 LLVMValueRef frame_result_loc;
3812 LLVMValueRef awaiter_init_val;
3813 LLVMValueRef ret_ptr;
3814 if (callee_is_async) {
3815 if (instruction->is_async) {
3816 if (instruction->new_stack == nullptr) {
3817 awaiter_init_val = zero;
3818 frame_result_loc = result_loc;
3819
3820 if (ret_has_bits) {
3821 // Use the result location which is inside the frame if this is an async call.
3822 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3823 }
3824 } else if (cc == CallingConventionAsync) {
3825 awaiter_init_val = zero;
3826 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3827 if (ir_want_runtime_safety(g, &instruction->base)) {
3828 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3829 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3830 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3831
3832 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3833 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3834
3835 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3836 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
3837
3838 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3839 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
3840
3841 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3842 }
3843 LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
3844 LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
3845 frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
3846 get_llvm_type(g, instruction->base.value.type), "");
3847
3848 if (ret_has_bits) {
3849 // Use the result location provided to the @asyncCall builtin
3850 ret_ptr = result_loc;
3851 }
3852 } else {
3853 zig_unreachable();
3854 }
3855
3856 // even if prefix_arg_err_ret_stack is true, let the async function do its own
3857 // initialization.
3858 } else {
3859 // async function called as a normal function
3860
3861 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
3862 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer
3863 if (ret_has_bits) {
3864 if (result_loc == nullptr) {
3865 // return type is a scalar, but we still need a pointer to it. Use the async fn frame.
3866 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3867 } else {
3868 // Use the call instruction's result location.
3869 ret_ptr = result_loc;
3870 }
3871
3872 // Store a zero in the awaiter's result ptr to indicate we do not need a copy made.
3873 LLVMValueRef awaiter_ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 1, "");
3874 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr)));
3875 LLVMBuildStore(g->builder, zero_ptr, awaiter_ret_ptr);
3876 }
3877
3878 if (prefix_arg_err_ret_stack) {
3879 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3880 frame_index_trace_arg(g, src_return_type) + 1, "");
3881 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
3882 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
3883 }
3884 }
36583885
3659 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, "");
3660 gen_param_values.append(err_val_ptr);
3886 assert(frame_result_loc != nullptr);
3887
3888 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_fn_ptr_index, "");
3889 LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val,
3890 LLVMGetElementType(LLVMTypeOf(fn_ptr_ptr)), "");
3891 LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr);
3892
3893 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_resume_index, "");
3894 LLVMBuildStore(g->builder, zero, resume_index_ptr);
3895
3896 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_awaiter_index, "");
3897 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3898
3899 if (ret_has_bits) {
3900 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3901 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3902 }
3903 } else if (instruction->is_async) {
3904 // Async call of blocking function
3905 if (instruction->new_stack != nullptr) {
3906 zig_panic("TODO @asyncCall of non-async function");
3907 }
3908 frame_result_loc = result_loc;
3909 awaiter_init_val = LLVMConstAllOnes(usize_type_ref);
3910
3911 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_awaiter_index, "");
3912 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
3913
3914 if (ret_has_bits) {
3915 LLVMValueRef ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3916 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, "");
3917 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3918
3919 if (first_arg_ret) {
3920 gen_param_values.append(ret_ptr);
3921 }
3922 if (prefix_arg_err_ret_stack) {
3923 // Set up the callee stack trace pointer pointing into the frame.
3924 // Then we have to wire up the StackTrace pointers.
3925 // Await is responsible for merging error return traces.
3926 uint32_t trace_field_index_start = frame_index_trace_arg(g, src_return_type);
3927 LLVMValueRef callee_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3928 trace_field_index_start, "");
3929 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3930 trace_field_index_start + 2, "");
3931 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3932 trace_field_index_start + 3, "");
3933
3934 LLVMBuildStore(g->builder, trace_field_ptr, callee_trace_ptr_ptr);
3935
3936 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
3937
3938 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3939 }
3940 }
3941 } else {
3942 if (first_arg_ret) {
3943 gen_param_values.append(result_loc);
3944 }
3945 if (prefix_arg_err_ret_stack) {
3946 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3947 }
36613948 }
36623949 FnWalk fn_walk = {};
36633950 fn_walk.id = FnWalkIdCall;
36643951 fn_walk.data.call.inst = instruction;
36653952 fn_walk.data.call.is_var_args = is_var_args;
36663953 fn_walk.data.call.gen_param_values = &gen_param_values;
3954 fn_walk.data.call.gen_param_types = &gen_param_types;
36673955 walk_function_params(g, fn_type, &fn_walk);
36683956
36693957 ZigLLVM_FnInline fn_inline;
......@@ -3679,12 +3967,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36793967 break;
36803968 }
36813969
3682 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3683 LLVMValueRef result;
3684
3970 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3971 LLVMValueRef result;
3972
3973 if (callee_is_async) {
3974 uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3975
3976 LLVMValueRef casted_frame;
3977 if (instruction->new_stack != nullptr) {
3978 // We need the frame type to be a pointer to a struct that includes the args
3979 size_t field_count = arg_start_i + gen_param_values.length;
3980 LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count);
3981 LLVMGetStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc)), field_types);
3982 assert(LLVMCountStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc))) == arg_start_i);
3983 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3984 field_types[arg_start_i + arg_i] = LLVMTypeOf(gen_param_values.at(arg_i));
3985 }
3986 LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false);
3987 LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0);
3988
3989 casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, "");
3990 } else {
3991 casted_frame = frame_result_loc;
3992 }
3993
3994 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3995 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, casted_frame, arg_start_i + arg_i, "");
3996 gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true),
3997 gen_param_values.at(arg_i));
3998 }
3999
4000 if (instruction->is_async) {
4001 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
4002 if (instruction->new_stack != nullptr) {
4003 return frame_result_loc;
4004 }
4005 return nullptr;
4006 } else {
4007 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
4008
4009 LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume");
4010
4011 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
4012 set_tail_call_if_appropriate(g, call_inst);
4013 LLVMBuildRetVoid(g->builder);
4014
4015 LLVMPositionBuilderAtEnd(g->builder, call_bb);
4016 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
4017 render_async_var_decls(g, instruction->base.scope);
4018
4019 if (!type_has_bits(src_return_type))
4020 return nullptr;
4021
4022 if (result_loc != nullptr)
4023 return get_handle_value(g, result_loc, src_return_type, ptr_result_type);
4024
4025 LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
4026 return LLVMBuildLoad(g->builder, result_ptr, "");
4027 }
4028 }
4029
36854030 if (instruction->new_stack == nullptr) {
36864031 result = ZigLLVMBuildCall(g->builder, fn_val,
36874032 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
4033 } else if (instruction->is_async) {
4034 zig_panic("TODO @asyncCall of non-async function");
36884035 } else {
36894036 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
36904037 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
......@@ -3697,13 +4044,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
36974044 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
36984045 }
36994046
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
37074047 if (src_return_type->id == ZigTypeIdUnreachable) {
37084048 return LLVMBuildUnreachable(g->builder);
37094049 } else if (!ret_has_bits) {
......@@ -4200,7 +4540,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
42004540 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
42014541 addLLVMFnAttr(fn_val, "nounwind");
42024542 add_uwtable_attr(g, fn_val);
4203 if (g->build_mode == BuildModeDebug) {
4543 if (codegen_have_frame_pointer(g)) {
42044544 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
42054545 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
42064546 }
......@@ -4347,10 +4687,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
43474687 {
43484688 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
43494689 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");
43544690 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
43554691 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
43564692 align_bytes = get_ptr_align(g, slice_ptr_type);
......@@ -4388,26 +4724,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
43884724{
43894725 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
43904726 if (cur_err_ret_trace_val == nullptr) {
4391 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
4392 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
4727 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
43934728 }
43944729 return cur_err_ret_trace_val;
43954730}
43964731
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
44114732static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
44124733 switch (atomic_order) {
44134734 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -4722,24 +5043,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
47225043 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
47235044}
47245045
4725static LLVMValueRef get_handle_fn_val(CodeGen *g) {
4726 if (g->coro_frame_fn_val)
4727 return g->coro_frame_fn_val;
4728
4729 LLVMTypeRef fn_type = LLVMFunctionType( LLVMPointerType(LLVMInt8Type(), 0)
4730 , nullptr, 0, false);
4731 Buf *name = buf_sprintf("llvm.coro.frame");
4732 g->coro_frame_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
4733 assert(LLVMGetIntrinsicID(g->coro_frame_fn_val));
4734
4735 return g->coro_frame_fn_val;
4736}
4737
4738static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
4739 IrInstructionHandle *instruction)
4740{
4741 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_promise));
4742 return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
5046static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable, IrInstructionFrameHandle *instruction) {
5047 return g->cur_frame_ptr;
47435048}
47445049
47455050static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
......@@ -5005,248 +5310,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
50055310 return nullptr;
50065311}
50075312
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
52505313static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
52515314 IrInstructionAtomicRmw *instruction)
52525315{
......@@ -5263,14 +5326,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
52635326 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
52645327
52655328 if (get_codegen_ptr_type(operand_type) == nullptr) {
5266 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, false);
5329 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
52675330 }
52685331
52695332 // it's a pointer but we need to treat it as an int
52705333 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
52715334 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
52725335 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);
5336 LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
5337 g->is_single_threaded);
52745338 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
52755339}
52765340
......@@ -5284,27 +5348,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
52845348 return load_inst;
52855349}
52865350
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
53085351static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
53095352 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
53105353 assert(instruction->base.value.type->id == ZigTypeIdFloat);
......@@ -5424,6 +5467,176 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
54245467 return nullptr;
54255468}
54265469
5470static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable,
5471 IrInstructionSuspendBegin *instruction)
5472{
5473 if (fn_is_async(g->cur_fn)) {
5474 instruction->resume_bb = gen_suspend_begin(g, "SuspendResume");
5475 }
5476 return nullptr;
5477}
5478
5479static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executable,
5480 IrInstructionSuspendFinish *instruction)
5481{
5482 LLVMBuildRetVoid(g->builder);
5483
5484 LLVMPositionBuilderAtEnd(g->builder, instruction->begin->resume_bb);
5485 render_async_var_decls(g, instruction->base.scope);
5486 return nullptr;
5487}
5488
5489static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {
5490 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5491 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
5492 LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame);
5493 ZigType *result_type = instruction->base.value.type;
5494 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
5495
5496 // Prepare to be suspended
5497 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");
5498 LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd");
5499
5500 // At this point resuming the function will continue from resume_bb.
5501 // This code is as if it is running inside the suspend block.
5502
5503 // supply the awaiter return pointer
5504 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
5505 nullptr : ir_llvm_value(g, instruction->result_loc);
5506 if (type_has_bits(result_type)) {
5507 LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, "");
5508 if (result_loc == nullptr) {
5509 // no copy needed
5510 LLVMBuildStore(g->builder, LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr_ptr))),
5511 awaiter_ret_ptr_ptr);
5512 } else {
5513 LLVMBuildStore(g->builder, result_loc, awaiter_ret_ptr_ptr);
5514 }
5515 }
5516
5517 // supply the error return trace pointer
5518 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5519 LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
5520 assert(my_err_ret_trace_val != nullptr);
5521 LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5522 frame_index_trace_arg(g, result_type) + 1, "");
5523 LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr);
5524 }
5525
5526 // caller's own frame pointer
5527 LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, "");
5528 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_awaiter_index, "");
5529 LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val,
5530 LLVMAtomicOrderingRelease);
5531
5532 LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait");
5533 LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend");
5534 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
5535
5536 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
5537 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2);
5538
5539 LLVMAddCase(switch_instr, zero, complete_suspend_block);
5540 LLVMAddCase(switch_instr, all_ones, early_return_block);
5541
5542 // We discovered that another awaiter was already here.
5543 LLVMPositionBuilderAtEnd(g->builder, bad_await_block);
5544 gen_assertion(g, PanicMsgIdBadAwait, &instruction->base);
5545
5546 // Rely on the target to resume us from suspension.
5547 LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block);
5548 LLVMBuildRetVoid(g->builder);
5549
5550 // Early return: The async function has already completed. We must copy the result and
5551 // the error return trace if applicable.
5552 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5553 if (type_has_bits(result_type) && result_loc != nullptr) {
5554 LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, "");
5555 LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, "");
5556 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
5557 LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, "");
5558 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, "");
5559 bool is_volatile = false;
5560 uint32_t abi_align = get_abi_alignment(g, result_type);
5561 LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false);
5562 ZigLLVMBuildMemCpy(g->builder,
5563 dest_ptr_casted, abi_align,
5564 src_ptr_casted, abi_align, byte_count_val, is_volatile);
5565 }
5566 if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) {
5567 LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr,
5568 frame_index_trace_arg(g, result_type), "");
5569 LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, "");
5570 LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
5571 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
5572 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2,
5573 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
5574 }
5575 LLVMBuildBr(g->builder, end_bb);
5576
5577 LLVMPositionBuilderAtEnd(g->builder, resume_bb);
5578 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr);
5579 LLVMBuildBr(g->builder, end_bb);
5580
5581 LLVMPositionBuilderAtEnd(g->builder, end_bb);
5582 if (type_has_bits(result_type) && result_loc != nullptr) {
5583 return get_handle_value(g, result_loc, result_type, ptr_result_type);
5584 }
5585 return nullptr;
5586}
5587
5588static LLVMValueRef ir_render_resume(CodeGen *g, IrExecutable *executable, IrInstructionResume *instruction) {
5589 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);
5590 ZigType *frame_type = instruction->frame->value.type;
5591 assert(frame_type->id == ZigTypeIdAnyFrame);
5592
5593 gen_resume(g, nullptr, frame, ResumeIdManual);
5594 return nullptr;
5595}
5596
5597static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,
5598 IrInstructionFrameSizeGen *instruction)
5599{
5600 LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
5601 return gen_frame_size(g, fn_val);
5602}
5603
5604static LLVMValueRef ir_render_spill_begin(CodeGen *g, IrExecutable *executable,
5605 IrInstructionSpillBegin *instruction)
5606{
5607 if (!fn_is_async(g->cur_fn))
5608 return nullptr;
5609
5610 switch (instruction->spill_id) {
5611 case SpillIdInvalid:
5612 zig_unreachable();
5613 case SpillIdRetErrCode: {
5614 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
5615 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5616 LLVMBuildStore(g->builder, operand, ptr);
5617 return nullptr;
5618 }
5619
5620 }
5621 zig_unreachable();
5622}
5623
5624static LLVMValueRef ir_render_spill_end(CodeGen *g, IrExecutable *executable, IrInstructionSpillEnd *instruction) {
5625 if (!fn_is_async(g->cur_fn))
5626 return ir_llvm_value(g, instruction->begin->operand);
5627
5628 switch (instruction->begin->spill_id) {
5629 case SpillIdInvalid:
5630 zig_unreachable();
5631 case SpillIdRetErrCode: {
5632 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5633 return LLVMBuildLoad(g->builder, ptr, "");
5634 }
5635
5636 }
5637 zig_unreachable();
5638}
5639
54275640static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
54285641 AstNode *source_node = instruction->source_node;
54295642 Scope *scope = instruction->scope;
......@@ -5445,7 +5658,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54455658 case IrInstructionIdSetRuntimeSafety:
54465659 case IrInstructionIdSetFloatMode:
54475660 case IrInstructionIdArrayType:
5448 case IrInstructionIdPromiseType:
5661 case IrInstructionIdAnyFrameType:
54495662 case IrInstructionIdSliceType:
54505663 case IrInstructionIdSizeOf:
54515664 case IrInstructionIdSwitchTarget:
......@@ -5485,8 +5698,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
54855698 case IrInstructionIdTagType:
54865699 case IrInstructionIdExport:
54875700 case IrInstructionIdErrorUnion:
5488 case IrInstructionIdPromiseResultType:
5489 case IrInstructionIdAwaitBookkeeping:
54905701 case IrInstructionIdAddImplicitReturnType:
54915702 case IrInstructionIdIntCast:
54925703 case IrInstructionIdFloatCast:
......@@ -5508,17 +5719,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55085719 case IrInstructionIdCallSrc:
55095720 case IrInstructionIdAllocaSrc:
55105721 case IrInstructionIdEndExpr:
5511 case IrInstructionIdAllocaGen:
55125722 case IrInstructionIdImplicitCast:
55135723 case IrInstructionIdResolveResult:
55145724 case IrInstructionIdResetResult:
5515 case IrInstructionIdResultPtr:
55165725 case IrInstructionIdContainerInitList:
55175726 case IrInstructionIdSliceSrc:
55185727 case IrInstructionIdRef:
55195728 case IrInstructionIdBitCastSrc:
55205729 case IrInstructionIdTestErrSrc:
55215730 case IrInstructionIdUnionInitNamedField:
5731 case IrInstructionIdFrameType:
5732 case IrInstructionIdFrameSizeSrc:
5733 case IrInstructionIdAllocaGen:
5734 case IrInstructionIdAwaitSrc:
55225735 zig_unreachable();
55235736
55245737 case IrInstructionIdDeclVarGen:
......@@ -5597,8 +5810,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55975810 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
55985811 case IrInstructionIdFrameAddress:
55995812 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
5600 case IrInstructionIdHandle:
5601 return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
5813 case IrInstructionIdFrameHandle:
5814 return ir_render_handle(g, executable, (IrInstructionFrameHandle *)instruction);
56025815 case IrInstructionIdOverflowOp:
56035816 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
56045817 case IrInstructionIdTestErrGen:
......@@ -5641,44 +5854,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
56415854 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
56425855 case IrInstructionIdErrorReturnTrace:
56435856 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);
56725857 case IrInstructionIdAtomicRmw:
56735858 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
56745859 case IrInstructionIdAtomicLoad:
56755860 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
56765861 case IrInstructionIdSaveErrRetAddr:
56775862 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);
56825863 case IrInstructionIdFloatOp:
56835864 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
56845865 case IrInstructionIdMulAdd:
......@@ -5695,6 +5876,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
56955876 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
56965877 case IrInstructionIdPtrOfArrayToSlice:
56975878 return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction);
5879 case IrInstructionIdSuspendBegin:
5880 return ir_render_suspend_begin(g, executable, (IrInstructionSuspendBegin *)instruction);
5881 case IrInstructionIdSuspendFinish:
5882 return ir_render_suspend_finish(g, executable, (IrInstructionSuspendFinish *)instruction);
5883 case IrInstructionIdResume:
5884 return ir_render_resume(g, executable, (IrInstructionResume *)instruction);
5885 case IrInstructionIdFrameSizeGen:
5886 return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction);
5887 case IrInstructionIdAwaitGen:
5888 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
5889 case IrInstructionIdSpillBegin:
5890 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
5891 case IrInstructionIdSpillEnd:
5892 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
56985893 }
56995894 zig_unreachable();
57005895}
......@@ -5704,6 +5899,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
57045899
57055900 IrExecutable *executable = &fn_entry->analyzed_executable;
57065901 assert(executable->basic_block_list.length > 0);
5902
57075903 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
57085904 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
57095905 assert(current_block->llvm_block);
......@@ -5894,7 +6090,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
58946090 case ZigTypeIdPointer:
58956091 case ZigTypeIdFn:
58966092 case ZigTypeIdOptional:
5897 case ZigTypeIdPromise:
58986093 {
58996094 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
59006095 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type);
......@@ -5957,7 +6152,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
59576152 }
59586153 return val;
59596154 }
5960
6155 case ZigTypeIdFnFrame:
6156 zig_panic("TODO bit pack an async function frame");
6157 case ZigTypeIdAnyFrame:
6158 zig_panic("TODO bit pack an anyframe");
59616159 }
59626160 zig_unreachable();
59636161}
......@@ -6110,6 +6308,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
61106308 break;
61116309 }
61126310
6311 if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull)))
6312 zig_unreachable();
6313
61136314 switch (type_entry->id) {
61146315 case ZigTypeIdInt:
61156316 return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint);
......@@ -6181,6 +6382,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
61816382 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
61826383 size_t src_field_count = type_entry->data.structure.src_field_count;
61836384 bool make_unnamed_struct = false;
6385 assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull);
61846386 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
61856387 size_t src_field_index = 0;
61866388 while (src_field_index < src_field_count) {
......@@ -6250,6 +6452,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
62506452 LLVMValueRef val = gen_const_val(g, field_val, "");
62516453 fields[type_struct_field->gen_index] = val;
62526454 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
6455
6456 size_t end_pad_gen_index = (i + 1 < src_field_count) ?
6457 type_entry->data.structure.fields[i + 1].gen_index :
6458 type_entry->data.structure.gen_field_count;
6459 size_t next_offset = (i + 1 < src_field_count) ?
6460 type_entry->data.structure.fields[i + 1].offset : type_entry->abi_size;
6461 if (end_pad_gen_index != SIZE_MAX) {
6462 for (size_t gen_i = type_struct_field->gen_index + 1; gen_i < end_pad_gen_index;
6463 gen_i += 1)
6464 {
6465 size_t pad_bytes = next_offset -
6466 (type_struct_field->offset + type_struct_field->type_entry->abi_size);
6467 LLVMTypeRef llvm_array_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
6468 fields[gen_i] = LLVMGetUndef(llvm_array_type);
6469 }
6470 }
62536471 }
62546472 }
62556473 if (make_unnamed_struct) {
......@@ -6437,30 +6655,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
64376655 err_payload_value = gen_const_val(g, payload_val, "");
64386656 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);
64396657 }
6658 LLVMValueRef fields[3];
6659 fields[err_union_err_index] = err_tag_value;
6660 fields[err_union_payload_index] = err_payload_value;
6661 size_t field_count = 2;
6662 if (type_entry->data.error_union.pad_llvm_type != nullptr) {
6663 fields[2] = LLVMGetUndef(type_entry->data.error_union.pad_llvm_type);
6664 field_count = 3;
6665 }
64406666 if (make_unnamed_struct) {
6441 uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, get_llvm_type(g, type_entry), 1);
6442 uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value));
6443 unsigned pad_sz = payload_off - err_sz;
6444 if (pad_sz == 0) {
6445 LLVMValueRef fields[] = {
6446 err_tag_value,
6447 err_payload_value,
6448 };
6449 return LLVMConstStruct(fields, 2, false);
6450 } else {
6451 LLVMValueRef fields[] = {
6452 err_tag_value,
6453 LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)),
6454 err_payload_value,
6455 };
6456 return LLVMConstStruct(fields, 3, false);
6457 }
6667 return LLVMConstStruct(fields, field_count, false);
64586668 } else {
6459 LLVMValueRef fields[] = {
6460 err_tag_value,
6461 err_payload_value,
6462 };
6463 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
6669 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count);
64646670 }
64656671 }
64666672 }
......@@ -6477,9 +6683,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
64776683 case ZigTypeIdBoundFn:
64786684 case ZigTypeIdArgTuple:
64796685 case ZigTypeIdOpaque:
6480 case ZigTypeIdPromise:
64816686 zig_unreachable();
6482
6687 case ZigTypeIdFnFrame:
6688 zig_panic("TODO");
6689 case ZigTypeIdAnyFrame:
6690 zig_panic("TODO");
64836691 }
64846692 zig_unreachable();
64856693}
......@@ -6563,12 +6771,20 @@ static void generate_error_name_table(CodeGen *g) {
65636771static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {
65646772 IrExecutable *executable = &fn->analyzed_executable;
65656773 assert(executable->basic_block_list.length > 0);
6774 LLVMValueRef fn_val = fn_llvm_value(g, fn);
6775 LLVMBasicBlockRef first_bb = nullptr;
6776 if (fn_is_async(fn)) {
6777 first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch");
6778 g->cur_preamble_llvm_block = first_bb;
6779 }
65666780 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
65676781 IrBasicBlock *bb = executable->basic_block_list.at(block_i);
6568 bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint);
6782 bb->llvm_block = LLVMAppendBasicBlock(fn_val, bb->name_hint);
6783 }
6784 if (first_bb == nullptr) {
6785 first_bb = executable->basic_block_list.at(0)->llvm_block;
65696786 }
6570 IrBasicBlock *entry_bb = executable->basic_block_list.at(0);
6571 LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
6787 LLVMPositionBuilderAtEnd(g->builder, first_bb);
65726788}
65736789
65746790static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
......@@ -6745,13 +6961,19 @@ static void do_code_gen(CodeGen *g) {
67456961 build_all_basic_blocks(g, fn_table_entry);
67466962 clear_debug_source_node(g);
67476963
6748 if (want_sret) {
6749 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6750 } else if (handle_is_ptr(fn_type_id->return_type)) {
6751 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
6752 // TODO add debug info variable for this
6964 bool is_async = fn_is_async(fn_table_entry);
6965
6966 if (is_async) {
6967 g->cur_frame_ptr = LLVMGetParam(fn, 0);
67536968 } else {
6754 g->cur_ret_ptr = nullptr;
6969 if (want_sret) {
6970 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6971 } else if (handle_is_ptr(fn_type_id->return_type)) {
6972 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
6973 // TODO add debug info variable for this
6974 } else {
6975 g->cur_ret_ptr = nullptr;
6976 }
67556977 }
67566978
67576979 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
......@@ -6763,39 +6985,45 @@ static void do_code_gen(CodeGen *g) {
67636985 }
67646986
67656987 // error return tracing setup
6766 bool is_async = cc == CallingConventionAsync;
6767 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;
6988 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
6989 !is_async && !have_err_ret_trace_arg;
67686990 LLVMValueRef err_ret_array_val = nullptr;
67696991 if (have_err_ret_trace_stack) {
67706992 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
67716993 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
67726994
6773 // populate g->stack_trace_type
6774 (void)get_ptr_to_stack_trace_type(g);
6775 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));
6995 (void)get_llvm_type(g, get_stack_trace_type(g));
6996 g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace",
6997 get_abi_alignment(g, g->stack_trace_type));
67766998 } else {
67776999 g->cur_err_ret_trace_val_stack = nullptr;
67787000 }
67797001
6780 // allocate temporary stack data
6781 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6782 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6783 ZigType *ptr_type = instruction->base.value.type;
6784 assert(ptr_type->id == ZigTypeIdPointer);
6785 ZigType *child_type = ptr_type->data.pointer.child_type;
6786 if (!type_has_bits(child_type))
6787 continue;
6788 if (instruction->base.ref_count == 0)
6789 continue;
6790 if (instruction->base.value.special != ConstValSpecialRuntime) {
6791 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
6792 ConstValSpecialRuntime)
6793 {
7002 if (!is_async) {
7003 // allocate temporary stack data
7004 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
7005 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
7006 ZigType *ptr_type = instruction->base.value.type;
7007 assert(ptr_type->id == ZigTypeIdPointer);
7008 ZigType *child_type = ptr_type->data.pointer.child_type;
7009 if (type_resolve(g, child_type, ResolveStatusSizeKnown))
7010 zig_unreachable();
7011 if (!type_has_bits(child_type))
7012 continue;
7013 if (instruction->base.ref_count == 0)
67947014 continue;
7015 if (instruction->base.value.special != ConstValSpecialRuntime) {
7016 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
7017 ConstValSpecialRuntime)
7018 {
7019 continue;
7020 }
67957021 }
7022 if (type_resolve(g, child_type, ResolveStatusLLVMFull))
7023 zig_unreachable();
7024 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
7025 get_ptr_align(g, ptr_type));
67967026 }
6797 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6798 get_ptr_align(g, ptr_type));
67997027 }
68007028
68017029 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
......@@ -6833,7 +7061,7 @@ static void do_code_gen(CodeGen *g) {
68337061 } else if (is_c_abi) {
68347062 fn_walk_var.data.vars.var = var;
68357063 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
6836 } else {
7064 } else if (!is_async) {
68377065 ZigType *gen_type;
68387066 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
68397067 assert(gen_info->gen_index != SIZE_MAX);
......@@ -6884,14 +7112,76 @@ static void do_code_gen(CodeGen *g) {
68847112 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
68857113 }
68867114
6887 // create debug variable declarations for parameters
6888 // rely on the first variables in the variable_list being parameters.
6889 FnWalk fn_walk_init = {};
6890 fn_walk_init.id = FnWalkIdInits;
6891 fn_walk_init.data.inits.fn = fn_table_entry;
6892 fn_walk_init.data.inits.llvm_fn = fn;
6893 fn_walk_init.data.inits.gen_i = gen_i_init;
6894 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
7115 if (is_async) {
7116 (void)get_llvm_type(g, fn_table_entry->frame_type);
7117 g->cur_resume_block_count = 0;
7118
7119 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
7120 LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
7121 ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
7122
7123 if (!g->strip_debug_symbols) {
7124 AstNode *source_node = fn_table_entry->proto_node;
7125 ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
7126 (int)source_node->column + 1, get_di_scope(g, fn_table_entry->child_scope));
7127 }
7128 IrExecutable *executable = &fn_table_entry->analyzed_executable;
7129 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
7130 LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
7131 gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope);
7132
7133 LLVMPositionBuilderAtEnd(g->builder, g->cur_preamble_llvm_block);
7134 render_async_spills(g);
7135 g->cur_async_awaiter_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_awaiter_index, "");
7136 LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_resume_index, "");
7137 g->cur_async_resume_index_ptr = resume_index_ptr;
7138
7139 if (type_has_bits(fn_type_id->return_type)) {
7140 LLVMValueRef cur_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start, "");
7141 g->cur_ret_ptr = LLVMBuildLoad(g->builder, cur_ret_ptr_ptr, "");
7142 }
7143 uint32_t trace_field_index_stack = UINT32_MAX;
7144 if (codegen_fn_has_err_ret_tracing_stack(g, fn_table_entry, true)) {
7145 trace_field_index_stack = frame_index_trace_stack(g, fn_type_id);
7146 g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7147 trace_field_index_stack, "");
7148 }
7149
7150 LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, "");
7151 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4);
7152 g->cur_async_switch_instr = switch_instr;
7153
7154 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
7155 IrBasicBlock *entry_block = executable->basic_block_list.at(0);
7156 LLVMAddCase(switch_instr, zero, entry_block->llvm_block);
7157 g->cur_resume_block_count += 1;
7158 LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block);
7159 if (trace_field_index_stack != UINT32_MAX) {
7160 if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) {
7161 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7162 frame_index_trace_arg(g, fn_type_id->return_type), "");
7163 LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(trace_ptr_ptr)));
7164 LLVMBuildStore(g->builder, zero_ptr, trace_ptr_ptr);
7165 }
7166
7167 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7168 trace_field_index_stack, "");
7169 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7170 trace_field_index_stack + 1, "");
7171
7172 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
7173 }
7174 render_async_var_decls(g, entry_block->instruction_list.at(0)->scope);
7175 } else {
7176 // create debug variable declarations for parameters
7177 // rely on the first variables in the variable_list being parameters.
7178 FnWalk fn_walk_init = {};
7179 fn_walk_init.id = FnWalkIdInits;
7180 fn_walk_init.data.inits.fn = fn_table_entry;
7181 fn_walk_init.data.inits.llvm_fn = fn;
7182 fn_walk_init.data.inits.gen_i = gen_i_init;
7183 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
7184 }
68957185
68967186 ir_render(g, fn_table_entry);
68977187
......@@ -6910,8 +7200,6 @@ static void do_code_gen(CodeGen *g) {
69107200 LLVMDumpModule(g->module);
69117201 }
69127202
6913 // in release mode, we're sooooo confident that we've generated correct ir,
6914 // that we skip the verify module step in order to get better performance.
69157203#ifndef NDEBUG
69167204 char *error = nullptr;
69177205 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
......@@ -7180,16 +7468,8 @@ static void define_builtin_types(CodeGen *g) {
71807468
71817469 g->primitive_type_table.put(&entry->name, entry);
71827470 }
7183 {
7184 ZigType *entry = get_promise_type(g, nullptr);
7185 g->primitive_type_table.put(&entry->name, entry);
7186 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
7187 entry->abi_align = g->builtin_types.entry_usize->abi_align;
7188 entry->abi_size = g->builtin_types.entry_usize->abi_size;
7189 }
71907471}
71917472
7192
71937473static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {
71947474 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
71957475 buf_init_from_str(&builtin_fn->name, name);
......@@ -7202,8 +7482,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
72027482static void define_builtin_fns(CodeGen *g) {
72037483 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
72047484 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
7205 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7206 create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
72077485 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
72087486 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
72097487 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
......@@ -7279,13 +7557,13 @@ static void define_builtin_fns(CodeGen *g) {
72797557 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
72807558 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
72817559 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7282 //Needs library support on Windows
7283 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7560 create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
72847561 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
72857562 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
72867563 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
72877564 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
72887565 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
7566 create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
72897567 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
72907568 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
72917569 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
......@@ -7304,6 +7582,10 @@ static void define_builtin_fns(CodeGen *g) {
73047582 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
73057583 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
73067584 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);
7585 create_builtin_fn(g, BuiltinFnIdFrameHandle, "frame", 0);
7586 create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1);
7587 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7588 create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
73077589}
73087590
73097591static const char *bool_to_str(bool b) {
......@@ -7615,7 +7897,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
76157897 " BoundFn: Fn,\n"
76167898 " ArgTuple: void,\n"
76177899 " Opaque: void,\n"
7618 " Promise: Promise,\n"
7900 " Frame: void,\n"
7901 " AnyFrame: AnyFrame,\n"
76197902 " Vector: Vector,\n"
76207903 " EnumLiteral: void,\n"
76217904 "\n\n"
......@@ -7728,11 +8011,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
77288011 " is_generic: bool,\n"
77298012 " is_var_args: bool,\n"
77308013 " return_type: ?type,\n"
7731 " async_allocator_type: ?type,\n"
77328014 " args: []FnArg,\n"
77338015 " };\n"
77348016 "\n"
7735 " pub const Promise = struct {\n"
8017 " pub const AnyFrame = struct {\n"
77368018 " child: ?type,\n"
77378019 " };\n"
77388020 "\n"
......@@ -8297,15 +8579,17 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
82978579 }
82988580
82998581 // According to Rich Felker libc headers are supposed to go before C language headers.
8582 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
8583 // and other compiler specific items.
8584 args.append("-isystem");
8585 args.append(buf_ptr(g->zig_c_headers_dir));
8586
83008587 for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
83018588 Buf *include_dir = g->libc_include_dir_list[i];
83028589 args.append("-isystem");
83038590 args.append(buf_ptr(include_dir));
83048591 }
83058592
8306 args.append("-isystem");
8307 args.append(buf_ptr(g->zig_c_headers_dir));
8308
83098593 if (g->zig_target->is_native) {
83108594 args.append("-march=native");
83118595 } else {
......@@ -8336,6 +8620,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83368620 args.append("-g");
83378621 }
83388622
8623 if (codegen_have_frame_pointer(g)) {
8624 args.append("-fno-omit-frame-pointer");
8625 } else {
8626 args.append("-fomit-frame-pointer");
8627 }
8628
83398629 switch (g->build_mode) {
83408630 case BuildModeDebug:
83418631 // windows c runtime requires -D_DEBUG if using debug libraries
......@@ -8348,7 +8638,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83488638 } else {
83498639 args.append("-fno-stack-protector");
83508640 }
8351 args.append("-fno-omit-frame-pointer");
83528641 break;
83538642 case BuildModeSafeRelease:
83548643 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
......@@ -8362,7 +8651,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83628651 } else {
83638652 args.append("-fno-stack-protector");
83648653 }
8365 args.append("-fomit-frame-pointer");
83668654 break;
83678655 case BuildModeFastRelease:
83688656 args.append("-DNDEBUG");
......@@ -8373,13 +8661,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
83738661 // running in -O2 and thus the -O3 path has been tested less.
83748662 args.append("-O2");
83758663 args.append("-fno-stack-protector");
8376 args.append("-fomit-frame-pointer");
83778664 break;
83788665 case BuildModeSmallRelease:
83798666 args.append("-DNDEBUG");
83808667 args.append("-Os");
83818668 args.append("-fno-stack-protector");
8382 args.append("-fomit-frame-pointer");
83838669 break;
83848670 }
83858671
......@@ -8907,7 +9193,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
89079193 case ZigTypeIdArgTuple:
89089194 case ZigTypeIdErrorUnion:
89099195 case ZigTypeIdErrorSet:
8910 case ZigTypeIdPromise:
9196 case ZigTypeIdFnFrame:
9197 case ZigTypeIdAnyFrame:
89119198 zig_unreachable();
89129199 case ZigTypeIdVoid:
89139200 case ZigTypeIdUnreachable:
......@@ -9091,7 +9378,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
90919378 case ZigTypeIdUndefined:
90929379 case ZigTypeIdNull:
90939380 case ZigTypeIdArgTuple:
9094 case ZigTypeIdPromise:
9381 case ZigTypeIdFnFrame:
9382 case ZigTypeIdAnyFrame:
90959383 zig_unreachable();
90969384 }
90979385}
......@@ -9258,9 +9546,11 @@ static void gen_h_file(CodeGen *g) {
92589546 case ZigTypeIdArgTuple:
92599547 case ZigTypeIdOptional:
92609548 case ZigTypeIdFn:
9261 case ZigTypeIdPromise:
92629549 case ZigTypeIdVector:
9550 case ZigTypeIdFnFrame:
9551 case ZigTypeIdAnyFrame:
92639552 zig_unreachable();
9553
92649554 case ZigTypeIdEnum:
92659555 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
92669556 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));
......@@ -9799,3 +10089,18 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
979910089 return g;
980010090}
980110091
10092bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type) {
10093 return g->have_err_ret_tracing &&
10094 (return_type->id == ZigTypeIdErrorUnion ||
10095 return_type->id == ZigTypeIdErrorSet);
10096}
10097
10098bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async) {
10099 if (is_async) {
10100 return g->have_err_ret_tracing && (fn->calls_or_awaits_errorable_fn ||
10101 codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type));
10102 } else {
10103 return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn &&
10104 !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type);
10105 }
10106}
src/codegen.hpp+2
......@@ -61,5 +61,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g);
6161TargetSubsystem detect_subsystem(CodeGen *g);
6262
6363void codegen_release_caches(CodeGen *codegen);
64bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type);
65bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async);
6466
6567#endif
src/ir.cpp+880-1712
......@@ -26,6 +26,7 @@ struct IrBuilder {
2626 CodeGen *codegen;
2727 IrExecutable *exec;
2828 IrBasicBlock *current_basic_block;
29 AstNode *main_block_node;
2930};
3031
3132struct IrAnalyze {
......@@ -99,7 +100,6 @@ struct ConstCastOnly {
99100 ConstCastErrUnionErrSetMismatch *error_union_error_set;
100101 ConstCastTypeMismatch *type_mismatch;
101102 ConstCastOnly *return_type;
102 ConstCastOnly *async_allocator_type;
103103 ConstCastOnly *null_wrap_ptr_child;
104104 ConstCastArg fn_arg;
105105 ConstCastArgNoAlias arg_no_alias;
......@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
305305 case ZigTypeIdBoundFn:
306306 case ZigTypeIdErrorSet:
307307 case ZigTypeIdOpaque:
308 case ZigTypeIdAnyFrame:
308309 return true;
309310 case ZigTypeIdFloat:
310311 return a->data.floating.bit_count == b->data.floating.bit_count;
......@@ -319,8 +320,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
319320 case ZigTypeIdUnion:
320321 case ZigTypeIdFn:
321322 case ZigTypeIdArgTuple:
322 case ZigTypeIdPromise:
323323 case ZigTypeIdVector:
324 case ZigTypeIdFnFrame:
324325 return false;
325326 }
326327 zig_unreachable();
......@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
565566 return IrInstructionIdArrayType;
566567}
567568
568static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {
569 return IrInstructionIdPromiseType;
569static constexpr IrInstructionId ir_instruction_id(IrInstructionAnyFrameType *) {
570 return IrInstructionIdAnyFrameType;
570571}
571572
572573static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
......@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
761762 return IrInstructionIdFrameAddress;
762763}
763764
764static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {
765 return IrInstructionIdHandle;
765static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameHandle *) {
766 return IrInstructionIdFrameHandle;
767}
768
769static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameType *) {
770 return IrInstructionIdFrameType;
771}
772
773static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeSrc *) {
774 return IrInstructionIdFrameSizeSrc;
775}
776
777static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeGen *) {
778 return IrInstructionIdFrameSizeGen;
766779}
767780
768781static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
......@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {
933946 return IrInstructionIdResetResult;
934947}
935948
936static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) {
937 return IrInstructionIdResultPtr;
938}
939
940949static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
941950 return IrInstructionIdPtrOfArrayToSlice;
942951}
......@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
961970 return IrInstructionIdErrorUnion;
962971}
963972
964static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) {
965 return IrInstructionIdCancel;
966}
967
968static constexpr IrInstructionId ir_instruction_id(IrInstructionGetImplicitAllocator *) {
969 return IrInstructionIdGetImplicitAllocator;
970}
971
972static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroId *) {
973 return IrInstructionIdCoroId;
974}
975
976static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAlloc *) {
977 return IrInstructionIdCoroAlloc;
978}
979
980static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSize *) {
981 return IrInstructionIdCoroSize;
982}
983
984static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroBegin *) {
985 return IrInstructionIdCoroBegin;
986}
987
988static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *) {
989 return IrInstructionIdCoroAllocFail;
990}
991
992static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) {
993 return IrInstructionIdCoroSuspend;
994}
995
996static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) {
997 return IrInstructionIdCoroEnd;
998}
999
1000static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) {
1001 return IrInstructionIdCoroFree;
1002}
1003
1004static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
1005 return IrInstructionIdCoroResume;
1006}
1007
1008static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
1009 return IrInstructionIdCoroSave;
1010}
1011
1012static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
1013 return IrInstructionIdCoroPromise;
1014}
1015
1016static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
1017 return IrInstructionIdCoroAllocHelper;
1018}
1019
1020973static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
1021974 return IrInstructionIdAtomicRmw;
1022975}
......@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
1025978 return IrInstructionIdAtomicLoad;
1026979}
1027980
1028static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
1029 return IrInstructionIdPromiseResultType;
1030}
1031
1032static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping *) {
1033 return IrInstructionIdAwaitBookkeeping;
1034}
1035
1036981static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
1037982 return IrInstructionIdSaveErrRetAddr;
1038983}
......@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
1041986 return IrInstructionIdAddImplicitReturnType;
1042987}
1043988
1044static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
1045 return IrInstructionIdMergeErrRetTraces;
1046}
1047
1048static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
1049 return IrInstructionIdMarkErrRetTracePtr;
1050}
1051
1052989static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1053990 return IrInstructionIdFloatOp;
1054991}
......@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi
10971034 return IrInstructionIdUnionInitNamedField;
10981035}
10991036
1037static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBegin *) {
1038 return IrInstructionIdSuspendBegin;
1039}
1040
1041static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendFinish *) {
1042 return IrInstructionIdSuspendFinish;
1043}
1044
1045static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitSrc *) {
1046 return IrInstructionIdAwaitSrc;
1047}
1048
1049static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitGen *) {
1050 return IrInstructionIdAwaitGen;
1051}
1052
1053static constexpr IrInstructionId ir_instruction_id(IrInstructionResume *) {
1054 return IrInstructionIdResume;
1055}
1056
1057static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillBegin *) {
1058 return IrInstructionIdSpillBegin;
1059}
1060
1061static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
1062 return IrInstructionIdSpillEnd;
1063}
1064
11001065template<typename T>
11011066static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
11021067 T *special_instruction = allocate<T>(1);
......@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
11491114}
11501115
11511116static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,
1152 IrInstruction *return_value)
1117 IrInstruction *operand)
11531118{
11541119 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);
11551120 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
11561121 return_instruction->base.value.special = ConstValSpecialStatic;
1157 return_instruction->value = return_value;
1122 return_instruction->operand = operand;
11581123
1159 if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block);
1124 if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block);
11601125
11611126 return &return_instruction->base;
11621127}
......@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode
12141179 return &const_instruction->base;
12151180}
12161181
1217static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) {
1218 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
1219 const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8;
1220 const_instruction->base.value.special = ConstValSpecialStatic;
1221 bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value);
1222 return &const_instruction->base;
1223}
1224
12251182static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
12261183 ZigType *type_entry)
12271184{
......@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
14291386
14301387static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
14311388 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1432 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
1389 bool is_comptime, FnInline fn_inline, bool is_async,
14331390 IrInstruction *new_stack, ResultLoc *result_loc)
14341391{
14351392 IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);
......@@ -1440,22 +1397,24 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
14401397 call_instruction->args = args;
14411398 call_instruction->arg_count = arg_count;
14421399 call_instruction->is_async = is_async;
1443 call_instruction->async_allocator = async_allocator;
14441400 call_instruction->new_stack = new_stack;
14451401 call_instruction->result_loc = result_loc;
14461402
14471403 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
14481404 for (size_t i = 0; i < arg_count; i += 1)
14491405 ir_ref_instruction(args[i], irb->current_basic_block);
1450 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
1406 if (is_async && new_stack != nullptr) {
1407 // in this case the arg at the end is the return pointer
1408 ir_ref_instruction(args[arg_count], irb->current_basic_block);
1409 }
14511410 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
14521411
14531412 return &call_instruction->base;
14541413}
14551414
1456static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
1415static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
14571416 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1458 FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack,
1417 FnInline fn_inline, bool is_async, IrInstruction *new_stack,
14591418 IrInstruction *result_loc, ZigType *return_type)
14601419{
14611420 IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,
......@@ -1467,18 +1426,16 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in
14671426 call_instruction->args = args;
14681427 call_instruction->arg_count = arg_count;
14691428 call_instruction->is_async = is_async;
1470 call_instruction->async_allocator = async_allocator;
14711429 call_instruction->new_stack = new_stack;
14721430 call_instruction->result_loc = result_loc;
14731431
14741432 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);
14751433 for (size_t i = 0; i < arg_count; i += 1)
14761434 ir_ref_instruction(args[i], ira->new_irb.current_basic_block);
1477 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block);
14781435 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);
14791436 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
14801437
1481 return &call_instruction->base;
1438 return call_instruction;
14821439}
14831440
14841441static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,
......@@ -1754,17 +1711,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
17541711 return &instruction->base;
17551712}
17561713
1757static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1714static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
17581715 IrInstruction *payload_type)
17591716{
1760 IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);
1717 IrInstructionAnyFrameType *instruction = ir_build_instruction<IrInstructionAnyFrameType>(irb, scope, source_node);
17611718 instruction->payload_type = payload_type;
17621719
17631720 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
17641721
17651722 return &instruction->base;
17661723}
1767
17681724static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
17691725 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
17701726{
......@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo
24432399}
24442400
24452401static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2446 IrInstructionHandle *instruction = ir_build_instruction<IrInstructionHandle>(irb, scope, source_node);
2402 IrInstructionFrameHandle *instruction = ir_build_instruction<IrInstructionFrameHandle>(irb, scope, source_node);
2403 return &instruction->base;
2404}
2405
2406static IrInstruction *ir_build_frame_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2407 IrInstructionFrameType *instruction = ir_build_instruction<IrInstructionFrameType>(irb, scope, source_node);
2408 instruction->fn = fn;
2409
2410 ir_ref_instruction(fn, irb->current_basic_block);
2411
2412 return &instruction->base;
2413}
2414
2415static IrInstruction *ir_build_frame_size_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2416 IrInstructionFrameSizeSrc *instruction = ir_build_instruction<IrInstructionFrameSizeSrc>(irb, scope, source_node);
2417 instruction->fn = fn;
2418
2419 ir_ref_instruction(fn, irb->current_basic_block);
2420
2421 return &instruction->base;
2422}
2423
2424static IrInstruction *ir_build_frame_size_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn)
2425{
2426 IrInstructionFrameSizeGen *instruction = ir_build_instruction<IrInstructionFrameSizeGen>(irb, scope, source_node);
2427 instruction->fn = fn;
2428
2429 ir_ref_instruction(fn, irb->current_basic_block);
2430
24472431 return &instruction->base;
24482432}
24492433
......@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s
25462530}
25472531
25482532static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
2549 IrInstruction *base_ptr, bool resolve_err_set)
2533 IrInstruction *base_ptr, bool resolve_err_set, bool base_ptr_is_payload)
25502534{
25512535 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);
25522536 instruction->base_ptr = base_ptr;
25532537 instruction->resolve_err_set = resolve_err_set;
2538 instruction->base_ptr_is_payload = base_ptr_is_payload;
25542539
25552540 ir_ref_instruction(base_ptr, irb->current_basic_block);
25562541
......@@ -2596,13 +2581,12 @@ static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope,
25962581
25972582static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
25982583 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
2599 IrInstruction *async_allocator_type_value, bool is_var_args)
2584 bool is_var_args)
26002585{
26012586 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
26022587 instruction->param_types = param_types;
26032588 instruction->align_value = align_value;
26042589 instruction->return_type = return_type;
2605 instruction->async_allocator_type_value = async_allocator_type_value;
26062590 instruction->is_var_args = is_var_args;
26072591
26082592 assert(source_node->type == NodeTypeFnProto);
......@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
26122596 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
26132597 }
26142598 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
2615 if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block);
26162599 ir_ref_instruction(return_type, irb->current_basic_block);
26172600
26182601 return &instruction->base;
......@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod
29942977 return &instruction->base;
29952978}
29962979
2997static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
2998 ResultLoc *result_loc, IrInstruction *result)
2999{
3000 IrInstructionResultPtr *instruction = ir_build_instruction<IrInstructionResultPtr>(irb, scope, source_node);
3001 instruction->result_loc = result_loc;
3002 instruction->result = result;
3003
3004 ir_ref_instruction(result, irb->current_basic_block);
3005
3006 return &instruction->base;
3007}
3008
30092980static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
30102981 IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
30112982
......@@ -3056,149 +3027,6 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
30563027 return &instruction->base;
30573028}
30583029
3059static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node,
3060 IrInstruction *target)
3061{
3062 IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
3063 instruction->target = target;
3064
3065 ir_ref_instruction(target, irb->current_basic_block);
3066
3067 return &instruction->base;
3068}
3069
3070static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node,
3071 ImplicitAllocatorId id)
3072{
3073 IrInstructionGetImplicitAllocator *instruction = ir_build_instruction<IrInstructionGetImplicitAllocator>(irb, scope, source_node);
3074 instruction->id = id;
3075
3076 return &instruction->base;
3077}
3078
3079static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) {
3080 IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);
3081 instruction->promise_ptr = promise_ptr;
3082
3083 ir_ref_instruction(promise_ptr, irb->current_basic_block);
3084
3085 return &instruction->base;
3086}
3087
3088static IrInstruction *ir_build_coro_alloc(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id) {
3089 IrInstructionCoroAlloc *instruction = ir_build_instruction<IrInstructionCoroAlloc>(irb, scope, source_node);
3090 instruction->coro_id = coro_id;
3091
3092 ir_ref_instruction(coro_id, irb->current_basic_block);
3093
3094 return &instruction->base;
3095}
3096
3097static IrInstruction *ir_build_coro_size(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3098 IrInstructionCoroSize *instruction = ir_build_instruction<IrInstructionCoroSize>(irb, scope, source_node);
3099
3100 return &instruction->base;
3101}
3102
3103static IrInstruction *ir_build_coro_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id, IrInstruction *coro_mem_ptr) {
3104 IrInstructionCoroBegin *instruction = ir_build_instruction<IrInstructionCoroBegin>(irb, scope, source_node);
3105 instruction->coro_id = coro_id;
3106 instruction->coro_mem_ptr = coro_mem_ptr;
3107
3108 ir_ref_instruction(coro_id, irb->current_basic_block);
3109 ir_ref_instruction(coro_mem_ptr, irb->current_basic_block);
3110
3111 return &instruction->base;
3112}
3113
3114static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_val) {
3115 IrInstructionCoroAllocFail *instruction = ir_build_instruction<IrInstructionCoroAllocFail>(irb, scope, source_node);
3116 instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
3117 instruction->base.value.special = ConstValSpecialStatic;
3118 instruction->err_val = err_val;
3119
3120 ir_ref_instruction(err_val, irb->current_basic_block);
3121
3122 return &instruction->base;
3123}
3124
3125static IrInstruction *ir_build_coro_suspend(IrBuilder *irb, Scope *scope, AstNode *source_node,
3126 IrInstruction *save_point, IrInstruction *is_final)
3127{
3128 IrInstructionCoroSuspend *instruction = ir_build_instruction<IrInstructionCoroSuspend>(irb, scope, source_node);
3129 instruction->save_point = save_point;
3130 instruction->is_final = is_final;
3131
3132 if (save_point != nullptr) ir_ref_instruction(save_point, irb->current_basic_block);
3133 ir_ref_instruction(is_final, irb->current_basic_block);
3134
3135 return &instruction->base;
3136}
3137
3138static IrInstruction *ir_build_coro_end(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3139 IrInstructionCoroEnd *instruction = ir_build_instruction<IrInstructionCoroEnd>(irb, scope, source_node);
3140 return &instruction->base;
3141}
3142
3143static IrInstruction *ir_build_coro_free(IrBuilder *irb, Scope *scope, AstNode *source_node,
3144 IrInstruction *coro_id, IrInstruction *coro_handle)
3145{
3146 IrInstructionCoroFree *instruction = ir_build_instruction<IrInstructionCoroFree>(irb, scope, source_node);
3147 instruction->coro_id = coro_id;
3148 instruction->coro_handle = coro_handle;
3149
3150 ir_ref_instruction(coro_id, irb->current_basic_block);
3151 ir_ref_instruction(coro_handle, irb->current_basic_block);
3152
3153 return &instruction->base;
3154}
3155
3156static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,
3157 IrInstruction *awaiter_handle)
3158{
3159 IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node);
3160 instruction->awaiter_handle = awaiter_handle;
3161
3162 ir_ref_instruction(awaiter_handle, irb->current_basic_block);
3163
3164 return &instruction->base;
3165}
3166
3167static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *source_node,
3168 IrInstruction *coro_handle)
3169{
3170 IrInstructionCoroSave *instruction = ir_build_instruction<IrInstructionCoroSave>(irb, scope, source_node);
3171 instruction->coro_handle = coro_handle;
3172
3173 ir_ref_instruction(coro_handle, irb->current_basic_block);
3174
3175 return &instruction->base;
3176}
3177
3178static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node,
3179 IrInstruction *coro_handle)
3180{
3181 IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node);
3182 instruction->coro_handle = coro_handle;
3183
3184 ir_ref_instruction(coro_handle, irb->current_basic_block);
3185
3186 return &instruction->base;
3187}
3188
3189static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
3190 IrInstruction *realloc_fn, IrInstruction *coro_size)
3191{
3192 IrInstructionCoroAllocHelper *instruction = ir_build_instruction<IrInstructionCoroAllocHelper>(irb, scope, source_node);
3193 instruction->realloc_fn = realloc_fn;
3194 instruction->coro_size = coro_size;
3195
3196 ir_ref_instruction(realloc_fn, irb->current_basic_block);
3197 ir_ref_instruction(coro_size, irb->current_basic_block);
3198
3199 return &instruction->base;
3200}
3201
32023030static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
32033031 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
32043032 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
......@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode
32383066 return &instruction->base;
32393067}
32403068
3241static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
3242 IrInstruction *promise_type)
3243{
3244 IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node);
3245 instruction->promise_type = promise_type;
3246
3247 ir_ref_instruction(promise_type, irb->current_basic_block);
3248
3249 return &instruction->base;
3250}
3251
3252static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, AstNode *source_node,
3253 IrInstruction *promise_result_type)
3254{
3255 IrInstructionAwaitBookkeeping *instruction = ir_build_instruction<IrInstructionAwaitBookkeeping>(irb, scope, source_node);
3256 instruction->promise_result_type = promise_result_type;
3257
3258 ir_ref_instruction(promise_result_type, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
32633069static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
32643070 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
32653071 return &instruction->base;
......@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
32763082 return &instruction->base;
32773083}
32783084
3279static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
3280 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
3281{
3282 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
3283 instruction->coro_promise_ptr = coro_promise_ptr;
3284 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
3285 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
3286
3287 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
3288 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
3289 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
3290
3291 return &instruction->base;
3292}
3293
3294static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
3295 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
3296 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
3297
3298 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
3299
3300 return &instruction->base;
3301}
3302
33033085static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
33043086 IrInstruction *container, IrInstruction *name)
33053087{
......@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode
34353217 return &instruction->base;
34363218}
34373219
3438static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3220static IrInstructionAllocaGen *ir_build_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
34393221 uint32_t align, const char *name_hint)
34403222{
34413223 IrInstructionAllocaGen *instruction = ir_create_instruction<IrInstructionAllocaGen>(&ira->new_irb,
......@@ -3459,6 +3241,87 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s
34593241 return &instruction->base;
34603242}
34613243
3244static IrInstructionSuspendBegin *ir_build_suspend_begin(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3245 IrInstructionSuspendBegin *instruction = ir_build_instruction<IrInstructionSuspendBegin>(irb, scope, source_node);
3246 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3247
3248 return instruction;
3249}
3250
3251static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstNode *source_node,
3252 IrInstructionSuspendBegin *begin)
3253{
3254 IrInstructionSuspendFinish *instruction = ir_build_instruction<IrInstructionSuspendFinish>(irb, scope, source_node);
3255 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3256 instruction->begin = begin;
3257
3258 ir_ref_instruction(&begin->base, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
3263static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
3264 IrInstruction *frame, ResultLoc *result_loc)
3265{
3266 IrInstructionAwaitSrc *instruction = ir_build_instruction<IrInstructionAwaitSrc>(irb, scope, source_node);
3267 instruction->frame = frame;
3268 instruction->result_loc = result_loc;
3269
3270 ir_ref_instruction(frame, irb->current_basic_block);
3271
3272 return &instruction->base;
3273}
3274
3275static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3276 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)
3277{
3278 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,
3279 source_instruction->scope, source_instruction->source_node);
3280 instruction->base.value.type = result_type;
3281 instruction->frame = frame;
3282 instruction->result_loc = result_loc;
3283
3284 ir_ref_instruction(frame, ira->new_irb.current_basic_block);
3285 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
3286
3287 return &instruction->base;
3288}
3289
3290static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {
3291 IrInstructionResume *instruction = ir_build_instruction<IrInstructionResume>(irb, scope, source_node);
3292 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3293 instruction->frame = frame;
3294
3295 ir_ref_instruction(frame, irb->current_basic_block);
3296
3297 return &instruction->base;
3298}
3299
3300static IrInstructionSpillBegin *ir_build_spill_begin(IrBuilder *irb, Scope *scope, AstNode *source_node,
3301 IrInstruction *operand, SpillId spill_id)
3302{
3303 IrInstructionSpillBegin *instruction = ir_build_instruction<IrInstructionSpillBegin>(irb, scope, source_node);
3304 instruction->base.value.special = ConstValSpecialStatic;
3305 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3306 instruction->operand = operand;
3307 instruction->spill_id = spill_id;
3308
3309 ir_ref_instruction(operand, irb->current_basic_block);
3310
3311 return instruction;
3312}
3313
3314static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode *source_node,
3315 IrInstructionSpillBegin *begin)
3316{
3317 IrInstructionSpillEnd *instruction = ir_build_instruction<IrInstructionSpillEnd>(irb, scope, source_node);
3318 instruction->begin = begin;
3319
3320 ir_ref_instruction(&begin->base, irb->current_basic_block);
3321
3322 return &instruction->base;
3323}
3324
34623325static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
34633326 results[ReturnKindUnconditional] = 0;
34643327 results[ReturnKindError] = 0;
......@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
34893352 continue;
34903353 case ScopeIdDeferExpr:
34913354 case ScopeIdCImport:
3492 case ScopeIdCoroPrelude:
34933355 zig_unreachable();
34943356 }
34953357 }
......@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
35453407 continue;
35463408 case ScopeIdDeferExpr:
35473409 case ScopeIdCImport:
3548 case ScopeIdCoroPrelude:
35493410 zig_unreachable();
35503411 }
35513412 }
......@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
35883449 return nullptr;
35893450}
35903451
3591static bool exec_is_async(IrExecutable *exec) {
3592 ZigFn *fn_entry = exec_fn_entry(exec);
3593 return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
3594}
3595
3596static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
3597 bool is_generated_code)
3598{
3599 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3600
3601 bool is_async = exec_is_async(irb->exec);
3602 if (!is_async) {
3603 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
3604 return_inst->is_gen = is_generated_code;
3605 return return_inst;
3606 }
3607
3608 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "Suspended");
3609 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "NotSuspended");
3610 IrBasicBlock *store_awaiter_block = ir_create_basic_block(irb, scope, "StoreAwaiter");
3611 IrBasicBlock *check_canceled_block = ir_create_basic_block(irb, scope, "CheckCanceled");
3612
3613 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
3614 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
3615 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
3616 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
3617 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
3618 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
3619 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
3620
3621 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
3622 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
3623 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
3624 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, ptr_mask, nullptr,
3625 AtomicRmwOp_or, AtomicOrderSeqCst);
3626
3627 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
3628 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
3629 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
3630
3631 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
3632 ir_build_unreachable(irb, scope, node);
3633
3634 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
3635 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
3636 // if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
3637 IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
3638 ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
3639
3640 ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
3641 IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
3642 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, await_handle);
3643 ir_build_br(irb, scope, node, irb->exec->coro_normal_final, is_comptime);
3644
3645 ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
3646 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
3647 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
3648 return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
3649}
3650
36513452static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {
36523453 assert(node->type == NodeTypeReturnExpr);
36533454
......@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
36893490 return_value = ir_build_const_void(irb, scope, node);
36903491 }
36913492
3493 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3494
36923495 size_t defer_counts[2];
36933496 ir_count_defers(irb, scope, outer_scope, defer_counts);
36943497 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3695 if (have_err_defers || irb->codegen->have_err_ret_tracing) {
3696 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3697 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
3698 if (!have_err_defers) {
3699 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3700 }
3498 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
3499 // only generate unconditional defers
3500 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3501 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3502 result_loc_ret->base.source_instruction = result;
3503 return result;
3504 }
3505 bool should_inline = ir_should_inline(irb->exec, scope);
37013506
3702 IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base,
3703 return_value);
3704 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false);
3507 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3508 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
37053509
3706 bool should_inline = ir_should_inline(irb->exec, scope);
3707 IrInstruction *is_comptime;
3708 if (should_inline) {
3709 is_comptime = ir_build_const_bool(irb, scope, node, true);
3710 } else {
3711 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3712 }
3510 if (!have_err_defers) {
3511 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3512 }
37133513
3714 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3715 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
3514 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
37163515
3717 ir_set_cursor_at_end_and_append_block(irb, err_block);
3718 if (have_err_defers) {
3719 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3720 }
3721 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3722 ir_build_save_err_ret_addr(irb, scope, node);
3723 }
3724 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3516 IrInstruction *is_comptime;
3517 if (should_inline) {
3518 is_comptime = ir_build_const_bool(irb, scope, node, should_inline);
3519 } else {
3520 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3521 }
37253522
3726 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3727 if (have_err_defers) {
3728 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3729 }
3730 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3523 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3524 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
37313525
3732 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3733 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);
3734 result_loc_ret->base.source_instruction = result;
3735 return result;
3736 } else {
3737 // generate unconditional defers
3526 ir_set_cursor_at_end_and_append_block(irb, err_block);
3527 if (have_err_defers) {
3528 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3529 }
3530 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3531 ir_build_save_err_ret_addr(irb, scope, node);
3532 }
3533 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3534
3535 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3536 if (have_err_defers) {
37383537 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3739 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);
3740 result_loc_ret->base.source_instruction = result;
3741 return result;
37423538 }
3539 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3540
3541 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3542 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3543 result_loc_ret->base.source_instruction = result;
3544 return result;
37433545 }
37443546 case ReturnKindError:
37453547 {
......@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
37473549 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
37483550 if (err_union_ptr == irb->codegen->invalid_instruction)
37493551 return irb->codegen->invalid_instruction;
3750 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true);
3552 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true, false);
37513553
37523554 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
37533555 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
......@@ -3761,19 +3563,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
37613563 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
37623564
37633565 ir_set_cursor_at_end_and_append_block(irb, return_block);
3566 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3567 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3568 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val));
3569 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3570 SpillIdRetErrCode);
3571 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3572 result_loc_ret->base.id = ResultLocIdReturn;
3573 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3574 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
37643575 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
3765 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3766 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3767
3768 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3769 result_loc_ret->base.id = ResultLocIdReturn;
3770 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3771 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
3772
37733576 if (irb->codegen->have_err_ret_tracing && !should_inline) {
37743577 ir_build_save_err_ret_addr(irb, scope, node);
37753578 }
3776 IrInstruction *ret_inst = ir_gen_async_return(irb, scope, node, err_val, false);
3579 err_val = ir_build_spill_end(irb, scope, node, spill_begin);
3580 IrInstruction *ret_inst = ir_build_return(irb, scope, node, err_val);
37773581 result_loc_ret->base.source_instruction = ret_inst;
37783582 }
37793583
......@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
39713775 incoming_values.append(else_expr_result);
39723776 }
39733777
3974 if (block_node->data.block.name != nullptr) {
3778 bool is_return_from_fn = block_node == irb->main_block_node;
3779 if (!is_return_from_fn) {
39753780 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3781 }
3782
3783 IrInstruction *result;
3784 if (block_node->data.block.name != nullptr) {
39763785 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
39773786 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
39783787 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
39793788 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3980 return ir_expr_wrap(irb, parent_scope, phi, result_loc);
3789 result = ir_expr_wrap(irb, parent_scope, phi, result_loc);
39813790 } else {
3982 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
39833791 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3984 return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
3792 result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
39853793 }
3794 if (!is_return_from_fn)
3795 return result;
3796
3797 // no need for save_err_ret_addr because this cannot return error
3798 // only generate unconditional defers
3799
3800 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result));
3801 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3802 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
39863803}
39873804
39883805static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
......@@ -4561,8 +4378,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
45614378 return irb->codegen->invalid_instruction;
45624379 }
45634380
4564 bool is_async = exec_is_async(irb->exec);
4565
45664381 switch (builtin_fn->id) {
45674382 case BuiltinFnIdInvalid:
45684383 zig_unreachable();
......@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
51855000 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);
51865001 case BuiltinFnIdFrameAddress:
51875002 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);
5188 case BuiltinFnIdHandle:
5003 case BuiltinFnIdFrameHandle:
51895004 if (!irb->exec->fn_entry) {
5190 add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
5191 return irb->codegen->invalid_instruction;
5192 }
5193 if (!is_async) {
5194 add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
5005 add_node_error(irb->codegen, node, buf_sprintf("@frame() called outside of function definition"));
51955006 return irb->codegen->invalid_instruction;
51965007 }
51975008 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);
5009 case BuiltinFnIdFrameType: {
5010 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5011 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5012 if (arg0_value == irb->codegen->invalid_instruction)
5013 return arg0_value;
5014
5015 IrInstruction *frame_type = ir_build_frame_type(irb, scope, node, arg0_value);
5016 return ir_lval_wrap(irb, scope, frame_type, lval, result_loc);
5017 }
5018 case BuiltinFnIdFrameSize: {
5019 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5020 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5021 if (arg0_value == irb->codegen->invalid_instruction)
5022 return arg0_value;
5023
5024 IrInstruction *frame_size = ir_build_frame_size_src(irb, scope, node, arg0_value);
5025 return ir_lval_wrap(irb, scope, frame_size, lval, result_loc);
5026 }
51985027 case BuiltinFnIdAlignOf:
51995028 {
52005029 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -5395,13 +5224,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
53955224 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
53965225
53975226 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5398 fn_inline, false, nullptr, nullptr, result_loc);
5227 fn_inline, false, nullptr, result_loc);
53995228 return ir_lval_wrap(irb, scope, call, lval, result_loc);
54005229 }
54015230 case BuiltinFnIdNewStackCall:
54025231 {
5403 if (node->data.fn_call_expr.params.length == 0) {
5404 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
5232 if (node->data.fn_call_expr.params.length < 2) {
5233 add_node_error(irb->codegen, node,
5234 buf_sprintf("expected at least 2 arguments, found %" ZIG_PRI_usize,
5235 node->data.fn_call_expr.params.length));
54055236 return irb->codegen->invalid_instruction;
54065237 }
54075238
......@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
54265257 }
54275258
54285259 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5429 FnInlineAuto, false, nullptr, new_stack, result_loc);
5260 FnInlineAuto, false, new_stack, result_loc);
5261 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5262 }
5263 case BuiltinFnIdAsyncCall:
5264 {
5265 size_t arg_offset = 3;
5266 if (node->data.fn_call_expr.params.length < arg_offset) {
5267 add_node_error(irb->codegen, node,
5268 buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
5269 arg_offset, node->data.fn_call_expr.params.length));
5270 return irb->codegen->invalid_instruction;
5271 }
5272
5273 AstNode *bytes_node = node->data.fn_call_expr.params.at(0);
5274 IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
5275 if (bytes == irb->codegen->invalid_instruction)
5276 return bytes;
5277
5278 AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1);
5279 IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
5280 if (ret_ptr == irb->codegen->invalid_instruction)
5281 return ret_ptr;
5282
5283 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2);
5284 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
5285 if (fn_ref == irb->codegen->invalid_instruction)
5286 return fn_ref;
5287
5288 size_t arg_count = node->data.fn_call_expr.params.length - arg_offset;
5289
5290 // last "arg" is return pointer
5291 IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
5292
5293 for (size_t i = 0; i < arg_count; i += 1) {
5294 AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset);
5295 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
5296 if (arg == irb->codegen->invalid_instruction)
5297 return arg;
5298 args[i] = arg;
5299 }
5300
5301 args[arg_count] = ret_ptr;
5302
5303 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5304 FnInlineAuto, true, bytes, result_loc);
54305305 return ir_lval_wrap(irb, scope, call, lval, result_loc);
54315306 }
54325307 case BuiltinFnIdTypeId:
......@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
57315606 }
57325607
57335608 bool is_async = node->data.fn_call_expr.is_async;
5734 IrInstruction *async_allocator = nullptr;
5735 if (is_async) {
5736 if (node->data.fn_call_expr.async_allocator) {
5737 async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
5738 if (async_allocator == irb->codegen->invalid_instruction)
5739 return async_allocator;
5740 }
5741 }
5742
5743 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
5744 is_async, async_allocator, nullptr, result_loc);
5609 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5610 FnInlineAuto, is_async, nullptr, result_loc);
57455611 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);
57465612}
57475613
......@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
62546120 LValPtr, nullptr);
62556121 if (err_val_ptr == irb->codegen->invalid_instruction)
62566122 return err_val_ptr;
6257 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, true);
6123 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr,
6124 true, false);
62586125 IrBasicBlock *after_cond_block = irb->current_basic_block;
62596126 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
62606127 IrInstruction *cond_br_inst;
......@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
67626629 }
67636630}
67646631
6765static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6766 assert(node->type == NodeTypePromiseType);
6632static IrInstruction *ir_gen_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6633 assert(node->type == NodeTypeAnyFrameType);
67676634
6768 AstNode *payload_type_node = node->data.promise_type.payload_type;
6635 AstNode *payload_type_node = node->data.anyframe_type.payload_type;
67696636 IrInstruction *payload_type_value = nullptr;
67706637
67716638 if (payload_type_node != nullptr) {
......@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
67756642
67766643 }
67776644
6778 return ir_build_promise_type(irb, scope, node, payload_type_value);
6645 return ir_build_anyframe_type(irb, scope, node, payload_type_value);
67796646}
67806647
67816648static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -7070,7 +6937,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
70706937 return err_val_ptr;
70716938
70726939 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
7073 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true);
6940 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true, false);
70746941
70756942 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
70766943 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
......@@ -7686,7 +7553,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
76867553 if (err_union_ptr == irb->codegen->invalid_instruction)
76877554 return irb->codegen->invalid_instruction;
76887555
7689 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true);
7556 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true, false);
76907557
76917558 IrInstruction *is_comptime;
76927559 if (ir_should_inline(irb->exec, parent_scope)) {
......@@ -7980,339 +7847,45 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
79807847 //return_type = nullptr;
79817848 }
79827849
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;
8072
8073 return ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
8074}
8075
8076static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode *node,
8077 IrInstruction *target_inst)
8078{
8079 IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "ResumeDone");
8080 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
8081 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "IsSuspended");
8082 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "IsNotSuspended");
8083
8084 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8085 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8086 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8087 IrInstruction *and_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, is_suspended_mask);
8088 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
8089 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8090 IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node,
8091 get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
8092
8093 // TODO relies on Zig not re-ordering fields
8094 IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst,
8095 false);
8096 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
8097 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8098 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8099 atomic_state_field_name, false);
8100
8101 // clear the is_suspended bit
8102 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8103 usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr,
8104 AtomicRmwOp_and, AtomicOrderSeqCst);
8105
8106 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8107 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8108 ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
8109
8110 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8111 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8112 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8113 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
8114
8115 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
8116 ir_build_unreachable(irb, scope, node);
8117
8118 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
8119 ir_build_coro_resume(irb, scope, node, target_inst);
8120 ir_build_br(irb, scope, node, done_block, is_comptime);
8121
8122 ir_set_cursor_at_end_and_append_block(irb, done_block);
8123 return ir_build_const_void(irb, scope, node);
7850 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
81247851}
81257852
81267853static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
81277854 assert(node->type == NodeTypeResume);
81287855
8129 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);
7856 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr);
81307857 if (target_inst == irb->codegen->invalid_instruction)
81317858 return irb->codegen->invalid_instruction;
81327859
8133 return ir_gen_resume_target(irb, scope, node, target_inst);
7860 return ir_build_resume(irb, scope, node, target_inst);
81347861}
81357862
8136static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
7863static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
7864 ResultLoc *result_loc)
7865{
81377866 assert(node->type == NodeTypeAwaitExpr);
81387867
8139 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
8140 if (target_inst == irb->codegen->invalid_instruction)
8141 return irb->codegen->invalid_instruction;
8142
81437868 ZigFn *fn_entry = exec_fn_entry(irb->exec);
81447869 if (!fn_entry) {
81457870 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
81467871 return irb->codegen->invalid_instruction;
81477872 }
8148 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
8149 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));
8150 return irb->codegen->invalid_instruction;
8151 }
8152
8153 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);
8154 if (scope_defer_expr) {
8155 if (!scope_defer_expr->reported_err) {
8156 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
8157 scope_defer_expr->reported_err = true;
7873 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
7874 if (existing_suspend_scope) {
7875 if (!existing_suspend_scope->reported_err) {
7876 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block"));
7877 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
7878 existing_suspend_scope->reported_err = true;
81587879 }
81597880 return irb->codegen->invalid_instruction;
81607881 }
81617882
8162 Scope *outer_scope = irb->exec->begin_scope;
7883 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr);
7884 if (target_inst == irb->codegen->invalid_instruction)
7885 return irb->codegen->invalid_instruction;
81637886
8164 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);
8165 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
8166 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8167
8168 if (irb->codegen->have_err_ret_tracing) {
8169 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8170 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8171 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8172 ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
8173 }
8174
8175 IrBasicBlock *already_awaited_block = ir_create_basic_block(irb, scope, "AlreadyAwaited");
8176 IrBasicBlock *not_awaited_block = ir_create_basic_block(irb, scope, "NotAwaited");
8177 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
8178 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, scope, "YesSuspend");
8179 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, scope, "NoSuspend");
8180 IrBasicBlock *merge_block = ir_create_basic_block(irb, scope, "MergeSuspend");
8181 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, scope, "SuspendCleanup");
8182 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "SuspendResume");
8183 IrBasicBlock *cancel_target_block = ir_create_basic_block(irb, scope, "CancelTarget");
8184 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
8185 IrBasicBlock *do_defers_block = ir_create_basic_block(irb, scope, "DoDefers");
8186 IrBasicBlock *destroy_block = ir_create_basic_block(irb, scope, "DestroyBlock");
8187 IrBasicBlock *my_suspended_block = ir_create_basic_block(irb, scope, "AlreadySuspended");
8188 IrBasicBlock *my_not_suspended_block = ir_create_basic_block(irb, scope, "NotAlreadySuspended");
8189 IrBasicBlock *do_suspend_block = ir_create_basic_block(irb, scope, "DoSuspend");
8190
8191 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8192 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8193 atomic_state_field_name, false);
8194
8195 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
8196 IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
8197 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
8198 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8199 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8200 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
8201 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8202 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
8203 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8204 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8205
8206 ZigVar *result_var = ir_create_var(irb, node, scope, nullptr,
8207 false, false, true, const_bool_false);
8208 IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
8209 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
8210 ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
8211 IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef, nullptr);
8212 build_decl_var_and_init(irb, scope, node, result_var, undef_promise_result, "result", const_bool_false);
8213 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
8214 ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
8215 IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
8216
8217 IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
8218 IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false);
8219 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8220 usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr,
8221 AtomicRmwOp_or, AtomicOrderSeqCst);
8222
8223 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
8224 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
8225 ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
8226
8227 ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
8228 ir_build_unreachable(irb, scope, node);
8229
8230 ir_set_cursor_at_end_and_append_block(irb, not_awaited_block);
8231 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8232 IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8233 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8234 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8235 ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
8236
8237 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8238 ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
8239
8240 ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
8241 ir_build_cancel(irb, scope, node, target_inst);
8242 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8243
8244 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
8245 if (irb->codegen->have_err_ret_tracing) {
8246 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8247 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8248 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8249 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
8250 }
8251 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8252 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8253 // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
8254 // because we're about to destroy the memory. So we store it into our result variable.
8255 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
8256 ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
8257 ir_build_cancel(irb, scope, node, target_inst);
8258 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8259
8260
8261 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
8262 IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8263 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8264 AtomicRmwOp_or, AtomicOrderSeqCst);
8265 IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
8266 IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
8267 ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
8268
8269 ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
8270 ir_build_unreachable(irb, scope, node);
8271
8272 ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
8273 IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
8274 IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
8275 ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
8276
8277 ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
8278 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
8279
8280 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8281 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8282 cases[0].block = resume_block;
8283 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8284 cases[1].block = destroy_block;
8285 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
8286 2, cases, const_bool_false, nullptr);
8287
8288 ir_set_cursor_at_end_and_append_block(irb, destroy_block);
8289 ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
8290 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8291
8292 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8293 IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false);
8294 IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8295 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr,
8296 AtomicRmwOp_or, AtomicOrderSeqCst);
8297 IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
8298 IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
8299 IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
8300 ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
8301
8302 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
8303 IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
8304 ir_gen_cancel_target(irb, scope, node, my_await_handle, true, false);
8305 ir_mark_gen(ir_build_br(irb, scope, node, do_defers_block, const_bool_false));
8306
8307 ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
8308 ir_gen_defers_for_block(irb, scope, outer_scope, true);
8309 ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
8310
8311 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8312 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8313
8314 ir_set_cursor_at_end_and_append_block(irb, merge_block);
8315 return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
7887 IrInstruction *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc);
7888 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
83167889}
83177890
83187891static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
......@@ -8323,20 +7896,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
83237896 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
83247897 return irb->codegen->invalid_instruction;
83257898 }
8326 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
8327 add_node_error(irb->codegen, node, buf_sprintf("suspend in non-async function"));
8328 return irb->codegen->invalid_instruction;
8329 }
8330
8331 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
8332 if (scope_defer_expr) {
8333 if (!scope_defer_expr->reported_err) {
8334 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
8335 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
8336 scope_defer_expr->reported_err = true;
8337 }
8338 return irb->codegen->invalid_instruction;
8339 }
83407899 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
83417900 if (existing_suspend_scope) {
83427901 if (!existing_suspend_scope->reported_err) {
......@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
83477906 return irb->codegen->invalid_instruction;
83487907 }
83497908
8350 Scope *outer_scope = irb->exec->begin_scope;
8351
8352 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
8353 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
8354 IrBasicBlock *suspended_block = ir_create_basic_block(irb, parent_scope, "AlreadySuspended");
8355 IrBasicBlock *canceled_block = ir_create_basic_block(irb, parent_scope, "IsCanceled");
8356 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, parent_scope, "NotCanceled");
8357 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, parent_scope, "NotAlreadySuspended");
8358 IrBasicBlock *cancel_awaiter_block = ir_create_basic_block(irb, parent_scope, "CancelAwaiter");
8359
8360 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_promise);
8361 IrInstruction *const_bool_true = ir_build_const_bool(irb, parent_scope, node, true);
8362 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
8363 IrInstruction *usize_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_usize);
8364 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, parent_scope, node, 0x1); // 0b001
8365 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, parent_scope, node, 0x2); // 0b010
8366 IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0);
8367 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, parent_scope, node, 0x7); // 0b111
8368 IrInstruction *ptr_mask = ir_build_un_op(irb, parent_scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8369
8370 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, parent_scope, node,
8371 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8372 AtomicRmwOp_or, AtomicOrderSeqCst);
8373
8374 IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8375 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8376 ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
8377
8378 ir_set_cursor_at_end_and_append_block(irb, canceled_block);
8379 IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8380 IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8381 IrBasicBlock *post_canceled_block = irb->current_basic_block;
8382 ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
8383
8384 ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
8385 IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
8386 ir_gen_cancel_target(irb, parent_scope, node, await_handle, true, false);
8387 IrBasicBlock *post_cancel_awaiter_block = irb->current_basic_block;
8388 ir_build_br(irb, parent_scope, node, cleanup_block, const_bool_false);
8389
8390 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8391 IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8392 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8393 ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
8394
8395 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
8396 ir_build_unreachable(irb, parent_scope, node);
8397
8398 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
8399 IrInstruction *suspend_code;
8400 if (node->data.suspend.block == nullptr) {
8401 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false);
8402 } else {
8403 Scope *child_scope;
7909 IrInstructionSuspendBegin *begin = ir_build_suspend_begin(irb, parent_scope, node);
7910 if (node->data.suspend.block != nullptr) {
84047911 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
8405 suspend_scope->resume_block = resume_block;
8406 child_scope = &suspend_scope->base;
8407 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
8408 ir_gen_node(irb, node->data.suspend.block, child_scope);
8409 suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
8410 }
8411
8412 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8413 cases[0].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 0));
8414 cases[0].block = resume_block;
8415 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
8416 cases[1].block = canceled_block;
8417 IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, parent_scope, node, suspend_code,
8418 irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8419 ir_mark_gen(&switch_br->base);
8420
8421 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8422 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8423 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8424 incoming_blocks[0] = post_canceled_block;
8425 incoming_values[0] = const_bool_true;
8426 incoming_blocks[1] = post_cancel_awaiter_block;
8427 incoming_values[1] = const_bool_false;
8428 IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values,
8429 nullptr);
8430 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
8431 ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
7912 Scope *child_scope = &suspend_scope->base;
7913 IrInstruction *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
7914 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
7915 }
84327916
8433 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8434 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
7917 return ir_mark_gen(ir_build_suspend_finish(irb, parent_scope, node, begin));
84357918}
84367919
84377920static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
......@@ -8523,8 +8006,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
85238006 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);
85248007 case NodeTypePointerType:
85258008 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);
8526 case NodeTypePromiseType:
8527 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc);
8009 case NodeTypeAnyFrameType:
8010 return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc);
85288011 case NodeTypeStringLiteral:
85298012 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);
85308013 case NodeTypeUndefinedLiteral:
......@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
85618044 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);
85628045 case NodeTypeErrorSetDecl:
85638046 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc);
8564 case NodeTypeCancel:
8565 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc);
85668047 case NodeTypeResume:
85678048 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);
85688049 case NodeTypeAwaitExpr:
8569 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval, result_loc);
8050 return ir_gen_await_expr(irb, scope, node, lval, result_loc);
85708051 case NodeTypeSuspend:
85718052 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);
85728053 case NodeTypeEnumLiteral:
......@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
86268107
86278108 irb->codegen = codegen;
86288109 irb->exec = ir_executable;
8110 irb->main_block_node = node;
86298111
86308112 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");
86318113 ir_set_cursor_at_end_and_append_block(irb, entry_block);
86328114 // Entry block gets a reference because we enter it to begin.
86338115 ir_ref_bb(irb->current_basic_block);
86348116
8635 ZigFn *fn_entry = exec_fn_entry(irb->exec);
8636
8637 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
8638 IrInstruction *coro_id;
8639 IrInstruction *u8_ptr_type;
8640 IrInstruction *const_bool_false;
8641 IrInstruction *coro_promise_ptr;
8642 IrInstruction *err_ret_trace_ptr;
8643 ZigType *return_type;
8644 Buf *result_ptr_field_name;
8645 ZigVar *coro_size_var;
8646 if (is_async) {
8647 // create the coro promise
8648 Scope *coro_scope = create_coro_prelude_scope(irb->codegen, node, scope);
8649 const_bool_false = ir_build_const_bool(irb, coro_scope, node, false);
8650 ZigVar *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8651
8652 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
8653 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
8654 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
8655 ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
8656 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
8657 IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef, nullptr);
8658 build_decl_var_and_init(irb, coro_scope, node, promise_var, undef_coro_frame, "promise", const_bool_false);
8659 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
8660
8661 ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8662 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
8663 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
8664 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
8665 IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value, nullptr);
8666 build_decl_var_and_init(irb, coro_scope, node, await_handle_var, null_await_handle, "await_handle", const_bool_false);
8667 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
8668
8669 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
8670 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
8671 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type,
8672 coro_promise_ptr, false);
8673 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
8674 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8675 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
8676 build_decl_var_and_init(irb, coro_scope, node, coro_size_var, coro_size, "coro_size", const_bool_false);
8677 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
8678 ImplicitAllocatorIdArg);
8679 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
8680 build_decl_var_and_init(irb, coro_scope, node, irb->exec->coro_allocator_var, implicit_allocator_ptr,
8681 "allocator", const_bool_false);
8682 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);
8683 IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name, false);
8684 IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr);
8685 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, realloc_fn, coro_size);
8686 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
8687 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
8688 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
8689 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
8690
8691 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
8692 // we can return undefined here, because the caller passes a pointer to the error struct field
8693 // in the error union result, and we populate it in case of allocation failure.
8694 ir_build_return(irb, coro_scope, node, undef);
8695
8696 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
8697 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr,
8698 false);
8699 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
8700
8701 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8702 irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8703 atomic_state_field_name, false);
8704 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8705 ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
8706 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8707 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8708 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
8709 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8710 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
8711 if (irb->codegen->have_err_ret_tracing) {
8712 // initialize the error return trace
8713 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
8714 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name, false);
8715
8716 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8717 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8718 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
8719
8720 // coordinate with builtin.zig
8721 Buf *index_name = buf_create_from_str("index");
8722 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name, false);
8723 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
8724
8725 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
8726 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false);
8727
8728 IrInstruction *slice_value = ir_build_slice_src(irb, scope, node, return_addresses_ptr, zero, nullptr, false, no_result_loc());
8729 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
8730 }
8731
8732
8733 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
8734 irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal");
8735 irb->exec->coro_suspend_block = ir_create_basic_block(irb, scope, "Suspend");
8736 irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
8737 }
8738
87398117 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
87408118 assert(result);
87418119 if (irb->exec->invalid)
87428120 return false;
87438121
87448122 if (!instr_is_unreachable(result)) {
8123 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));
87458124 // no need for save_err_ret_addr because this cannot return error
8746 ir_gen_async_return(irb, scope, result->source_node, result, true);
8747 }
8748
8749 if (is_async) {
8750 IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume");
8751 IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree");
8752
8753 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final);
8754 IrInstruction *const_bool_true = ir_build_const_bool(irb, scope, node, true);
8755 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, nullptr, const_bool_true);
8756 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8757 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8758 cases[0].block = invalid_resume_block;
8759 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8760 cases[1].block = irb->exec->coro_final_cleanup_block;
8761 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8762
8763 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
8764 ir_build_coro_end(irb, scope, node);
8765 ir_build_return(irb, scope, node, irb->exec->coro_handle);
8766
8767 ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block);
8768 ir_build_unreachable(irb, scope, node);
8769
8770 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
8771 if (type_has_bits(return_type)) {
8772 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8773 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8774 false, false, PtrLenUnknown, 0, 0, 0, false));
8775 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
8776 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8777 result_ptr, false);
8778 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node,
8779 u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false);
8780 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
8781 fn_entry->type_entry->data.fn.fn_type_id.return_type);
8782 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
8783 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
8784 }
8785 if (irb->codegen->have_err_ret_tracing) {
8786 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8787 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8788 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
8789 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
8790 }
8791 // Before we destroy the coroutine frame, we need to load the target promise into
8792 // a register or local variable which does not get spilled into the frame,
8793 // otherwise llvm tries to access memory inside the destroyed frame.
8794 IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
8795 irb->exec->await_handle_var_ptr, false, false);
8796 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
8797 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8798
8799 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
8800 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8801
8802 ir_set_cursor_at_end_and_append_block(irb, check_free_block);
8803 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8804 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8805 incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8806 incoming_values[0] = const_bool_false;
8807 incoming_blocks[1] = irb->exec->coro_normal_final;
8808 incoming_values[1] = const_bool_true;
8809 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr);
8810
8811 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
8812 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
8813 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8814 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
8815 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
8816 merge_incoming_values[1] = await_handle_in_block;
8817 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values, nullptr);
8818
8819 Buf *shrink_field_name = buf_create_from_str(ASYNC_SHRINK_FIELD_NAME);
8820 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
8821 ImplicitAllocatorIdLocalVar);
8822 IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name, false);
8823 IrInstruction *shrink_fn = ir_build_load_ptr(irb, scope, node, shrink_fn_ptr);
8824 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8825 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
8826 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8827 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8828 false, false, PtrLenUnknown, 0, 0, 0, false));
8829 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8830 coro_mem_ptr_maybe, false);
8831 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
8832 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
8833 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
8834 IrInstruction *mem_slice = ir_build_slice_src(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
8835 no_result_loc());
8836 size_t arg_count = 5;
8837 IrInstruction **args = allocate<IrInstruction *>(arg_count);
8838 args[0] = implicit_allocator_ptr; // self
8839 args[1] = mem_slice; // old_mem
8840 args[2] = ir_build_const_usize(irb, scope, node, 8); // old_align
8841 // TODO: intentional memory leak here. If this is set to 0 then there is an issue where a coroutine
8842 // calls the function and it frees its own stack frame, but then the return value is a slice, which
8843 // is implemented as an sret struct. writing to the return pointer causes invalid memory write.
8844 // We could work around it by having a global helper function which has a void return type
8845 // and calling that instead. But instead this hack will suffice until I rework coroutines to be
8846 // non-allocating. Basically coroutines are not supported right now until they are reworked.
8847 args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size
8848 args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align
8849 ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr,
8850 nullptr, no_result_loc());
8851
8852 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
8853 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
8854
8855 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8856 ir_gen_resume_target(irb, scope, node, awaiter_handle);
8857 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
8125 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
88588126 }
88598127
88608128 return true;
......@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
88718139 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);
88728140}
88738141
8874static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
8142static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
88758143 if (!exec || !exec->source_node || limit < 0) return;
88768144 add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));
88778145
8878 add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
8146 ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
8147}
8148
8149void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) {
8150 IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
8151 add_error_note(ira->codegen, err_msg, old_instruction->source_node, text);
8152 ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10);
88798153}
88808154
88818155static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
88828156 invalidate_exec(exec);
88838157 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
88848158 if (exec->parent_exec) {
8885 add_call_stack_errors(codegen, exec, err_msg, 10);
8159 ir_add_call_stack_errors(codegen, exec, err_msg, 10);
88868160 }
88878161 return err_msg;
88888162}
......@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec
89468220 IrInstruction *instruction = bb->instruction_list.at(i);
89478221 if (instruction->id == IrInstructionIdReturn) {
89488222 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;
8949 IrInstruction *value = ret_inst->value;
8950 if (value->value.special == ConstValSpecialRuntime) {
8951 exec_add_error_node(codegen, exec, value->source_node,
8223 IrInstruction *operand = ret_inst->operand;
8224 if (operand->value.special == ConstValSpecialRuntime) {
8225 exec_add_error_node(codegen, exec, operand->source_node,
89528226 buf_sprintf("unable to evaluate constant expression"));
89538227 return &codegen->invalid_instruction->value;
89548228 }
8955 return &value->value;
8229 return &operand->value;
89568230 } else if (ir_has_side_effects(instruction)) {
89578231 if (instr_is_comptime(instruction)) {
89588232 switch (instruction->id) {
......@@ -9713,6 +8987,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
97138987 bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat);
97148988 assert(const_val_is_int || const_val_is_float);
97158989
8990 if (const_val_is_int && other_type->id == ZigTypeIdComptimeFloat) {
8991 return true;
8992 }
97168993 if (other_type->id == ZigTypeIdFloat) {
97178994 if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) {
97188995 return true;
......@@ -10200,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
102009477 return result;
102019478 }
102029479
10203 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
10204 actual_type->id == ZigTypeIdPromise)
10205 {
10206 return result;
10207 }
10208
102099480 // fn
102109481 if (wanted_type->id == ZigTypeIdFn &&
102119482 actual_type->id == ZigTypeIdFn)
......@@ -10240,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
102409511 return result;
102419512 }
102429513 }
10243 if (!wanted_type->data.fn.is_generic && wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
10244 ConstCastOnly child = types_match_const_cast_only(ira,
10245 actual_type->data.fn.fn_type_id.async_allocator_type,
10246 wanted_type->data.fn.fn_type_id.async_allocator_type,
10247 source_node, false);
10248 if (child.id == ConstCastResultIdInvalid)
10249 return child;
10250 if (child.id != ConstCastResultIdOk) {
10251 result.id = ConstCastResultIdAsyncAllocatorType;
10252 result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
10253 *result.data.async_allocator_type = child;
10254 return result;
10255 }
10256 }
102579514 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
102589515 result.id = ConstCastResultIdFnArgCount;
102599516 return result;
......@@ -10358,6 +9615,10 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
103589615 return cur_type;
103599616 }
103609617
9618 if (prev_type == cur_type) {
9619 continue;
9620 }
9621
103619622 if (prev_type->id == ZigTypeIdUnreachable) {
103629623 prev_inst = cur_inst;
103639624 continue;
......@@ -10558,6 +9819,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
105589819
105599820 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
105609821 ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type;
9822 if (prev_err_set_type == cur_err_set_type)
9823 continue;
105619824
105629825 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
105639826 return ira->codegen->builtin_types.entry_invalid;
......@@ -11203,7 +10466,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,
1120310466}
1120410467
1120510468static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) {
11206 ir_assert(!old_bb->suspended, old_bb->instruction_list.at(0));
10469 ir_assert(!old_bb->suspended, (old_bb->instruction_list.length != 0) ? old_bb->instruction_list.at(0) : nullptr);
1120710470 ira->instruction_index = 0;
1120810471 ira->old_irb.current_basic_block = old_bb;
1120910472 ira->const_predecessor_bb = const_predecessor_bb;
......@@ -11726,6 +10989,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
1172610989 return result;
1172710990}
1172810991
10992static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr,
10993 IrInstruction *value, ZigType *wanted_type)
10994{
10995 if (instr_is_comptime(value)) {
10996 zig_panic("TODO comptime frame pointer");
10997 }
10998
10999 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
11000 wanted_type, value, CastOpBitCast);
11001 result->value.type = wanted_type;
11002 return result;
11003}
11004
11005static IrInstruction *ir_analyze_anyframe_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr,
11006 IrInstruction *value, ZigType *wanted_type)
11007{
11008 if (instr_is_comptime(value)) {
11009 zig_panic("TODO comptime anyframe->T to anyframe");
11010 }
11011
11012 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
11013 wanted_type, value, CastOpBitCast);
11014 result->value.type = wanted_type;
11015 return result;
11016}
11017
11018
1172911019static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
1173011020 ZigType *wanted_type, ResultLoc *result_loc)
1173111021{
......@@ -11935,7 +11225,6 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
1193511225 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
1193611226 enum_type->data.enumeration.src_field_count == 1)
1193711227 {
11938 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
1193911228 IrInstruction *result = ir_const(ira, source_instr, tag_type);
1194011229 init_const_bigint(&result->value, tag_type,
1194111230 &enum_type->data.enumeration.fields[0].value);
......@@ -12574,12 +11863,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou
1257411863static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {
1257511864 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;
1257611865 if (ty->id == ZigTypeIdFn) return true;
12577 if (ty->id == ZigTypeIdPromise) return true;
1257811866 if (ty->id == ZigTypeIdOptional) {
1257911867 ZigType *ptr_ty = ty->data.maybe.child_type;
1258011868 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;
1258111869 if (ptr_ty->id == ZigTypeIdFn) return true;
12582 if (ptr_ty->id == ZigTypeIdPromise) return true;
1258311870 }
1258411871 return false;
1258511872}
......@@ -12827,6 +12114,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1282712114 }
1282812115 }
1282912116
12117 // *@Frame(func) to anyframe->T or anyframe
12118 if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle &&
12119 !actual_type->data.pointer.is_const &&
12120 actual_type->data.pointer.child_type->id == ZigTypeIdFnFrame && wanted_type->id == ZigTypeIdAnyFrame)
12121 {
12122 bool ok = true;
12123 if (wanted_type->data.any_frame.result_type != nullptr) {
12124 ZigFn *fn = actual_type->data.pointer.child_type->data.frame.fn;
12125 ZigType *fn_return_type = fn->type_entry->data.fn.fn_type_id.return_type;
12126 if (wanted_type->data.any_frame.result_type != fn_return_type) {
12127 ok = false;
12128 }
12129 }
12130 if (ok) {
12131 return ir_analyze_frame_ptr_to_anyframe(ira, source_instr, value, wanted_type);
12132 }
12133 }
12134
12135 // anyframe->T to anyframe
12136 if (actual_type->id == ZigTypeIdAnyFrame && actual_type->data.any_frame.result_type != nullptr &&
12137 wanted_type->id == ZigTypeIdAnyFrame && wanted_type->data.any_frame.result_type == nullptr)
12138 {
12139 return ir_analyze_anyframe_to_anyframe(ira, source_instr, value, wanted_type);
12140 }
1283012141
1283112142 // cast from null literal to maybe type
1283212143 if (wanted_type->id == ZigTypeIdOptional &&
......@@ -13331,11 +12642,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
1333112642}
1333212643
1333312644static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {
13334 IrInstruction *value = instruction->value->child;
13335 if (type_is_invalid(value->value.type))
12645 IrInstruction *operand = instruction->operand->child;
12646 if (type_is_invalid(operand->value.type))
1333612647 return ir_unreach_error(ira);
1333712648
13338 if (!instr_is_comptime(value) && handle_is_ptr(ira->explicit_return_type)) {
12649 if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) {
1333912650 // result location mechanism took care of it.
1334012651 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
1334112652 instruction->base.source_node, nullptr);
......@@ -13343,8 +12654,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
1334312654 return ir_finish_anal(ira, result);
1334412655 }
1334512656
13346 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
13347 if (type_is_invalid(casted_value->value.type)) {
12657 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type);
12658 if (type_is_invalid(casted_operand->value.type)) {
1334812659 AstNode *source_node = ira->explicit_return_type_source_node;
1334912660 if (source_node != nullptr) {
1335012661 ErrorMsg *msg = ira->codegen->errors.last();
......@@ -13354,15 +12665,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
1335412665 return ir_unreach_error(ira);
1335512666 }
1335612667
13357 if (casted_value->value.special == ConstValSpecialRuntime &&
13358 casted_value->value.type->id == ZigTypeIdPointer &&
13359 casted_value->value.data.rh_ptr == RuntimeHintPtrStack)
12668 if (casted_operand->value.special == ConstValSpecialRuntime &&
12669 casted_operand->value.type->id == ZigTypeIdPointer &&
12670 casted_operand->value.data.rh_ptr == RuntimeHintPtrStack)
1336012671 {
13361 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
12672 ir_add_error(ira, casted_operand, buf_sprintf("function returns address of local variable"));
1336212673 return ir_unreach_error(ira);
1336312674 }
12675
1336412676 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
13365 instruction->base.source_node, casted_value);
12677 instruction->base.source_node, casted_operand);
1336612678 result->value.type = ira->codegen->builtin_types.entry_unreachable;
1336712679 return ir_finish_anal(ira, result);
1336812680}
......@@ -13656,9 +12968,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1365612968 case ZigTypeIdOpaque:
1365712969 case ZigTypeIdBoundFn:
1365812970 case ZigTypeIdArgTuple:
13659 case ZigTypeIdPromise:
1366012971 case ZigTypeIdEnum:
1366112972 case ZigTypeIdEnumLiteral:
12973 case ZigTypeIdAnyFrame:
1366212974 operator_allowed = is_equality_cmp;
1366312975 break;
1366412976
......@@ -13673,6 +12985,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
1367312985 case ZigTypeIdNull:
1367412986 case ZigTypeIdErrorUnion:
1367512987 case ZigTypeIdUnion:
12988 case ZigTypeIdFnFrame:
1367612989 operator_allowed = false;
1367712990 break;
1367812991 case ZigTypeIdOptional:
......@@ -15037,7 +14350,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1503714350 case ZigTypeIdBoundFn:
1503814351 case ZigTypeIdArgTuple:
1503914352 case ZigTypeIdOpaque:
15040 case ZigTypeIdPromise:
14353 case ZigTypeIdFnFrame:
14354 case ZigTypeIdAnyFrame:
1504114355 ir_add_error(ira, target,
1504214356 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));
1504314357 break;
......@@ -15061,8 +14375,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1506114375 case ZigTypeIdBoundFn:
1506214376 case ZigTypeIdArgTuple:
1506314377 case ZigTypeIdOpaque:
15064 case ZigTypeIdPromise:
1506514378 case ZigTypeIdEnumLiteral:
14379 case ZigTypeIdFnFrame:
14380 case ZigTypeIdAnyFrame:
1506614381 ir_add_error(ira, target,
1506714382 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));
1506814383 break;
......@@ -15089,8 +14404,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
1508914404static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1509014405 IrInstructionErrorReturnTrace *instruction)
1509114406{
14407 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false);
1509214408 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
15093 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
1509414409 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
1509514410 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
1509614411 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);
......@@ -15108,7 +14423,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1510814423 assert(ira->codegen->have_err_ret_tracing);
1510914424 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
1511014425 instruction->base.source_node, instruction->optional);
15111 new_instruction->value.type = get_ptr_to_stack_trace_type(ira->codegen);
14426 new_instruction->value.type = ptr_to_stack_trace_type;
1511214427 return new_instruction;
1511314428 }
1511414429}
......@@ -15140,42 +14455,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
1514014455 return ir_const_type(ira, &instruction->base, result_type);
1514114456}
1514214457
15143IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_instr, ImplicitAllocatorId id) {
15144 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
15145 if (parent_fn_entry == nullptr) {
15146 ir_add_error(ira, source_instr, buf_sprintf("no implicit allocator available"));
15147 return ira->codegen->invalid_instruction;
15148 }
15149
15150 FnTypeId *parent_fn_type = &parent_fn_entry->type_entry->data.fn.fn_type_id;
15151 if (parent_fn_type->cc != CallingConventionAsync) {
15152 ir_add_error(ira, source_instr, buf_sprintf("async function call from non-async caller requires allocator parameter"));
15153 return ira->codegen->invalid_instruction;
15154 }
15155
15156 assert(parent_fn_type->async_allocator_type != nullptr);
15157
15158 switch (id) {
15159 case ImplicitAllocatorIdArg:
15160 {
15161 IrInstruction *result = ir_build_get_implicit_allocator(&ira->new_irb, source_instr->scope,
15162 source_instr->source_node, ImplicitAllocatorIdArg);
15163 result->value.type = parent_fn_type->async_allocator_type;
15164 return result;
15165 }
15166 case ImplicitAllocatorIdLocalVar:
15167 {
15168 ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
15169 assert(coro_allocator_var != nullptr);
15170 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var);
15171 IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr);
15172 assert(result->value.type != nullptr);
15173 return result;
15174 }
15175 }
15176 zig_unreachable();
15177}
15178
1517914458static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,
1518014459 uint32_t align, const char *name_hint, bool force_comptime)
1518114460{
......@@ -15184,7 +14463,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in
1518414463 ConstExprValue *pointee = create_const_vals(1);
1518514464 pointee->special = ConstValSpecialUndef;
1518614465
15187 IrInstructionAllocaGen *result = ir_create_alloca_gen(ira, source_inst, align, name_hint);
14466 IrInstructionAllocaGen *result = ir_build_alloca_gen(ira, source_inst, align, name_hint);
1518814467 result->base.value.special = ConstValSpecialStatic;
1518914468 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
1519014469 result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer;
......@@ -15281,7 +14560,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1528114560 return nullptr;
1528214561 }
1528314562 // need to return a result location and don't have one. use a stack allocation
15284 IrInstructionAllocaGen *alloca_gen = ir_create_alloca_gen(ira, suspend_source_instr, 0, "");
14563 IrInstructionAllocaGen *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr, 0, "");
1528514564 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))
1528614565 return ira->codegen->invalid_instruction;
1528714566 alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false,
......@@ -15351,8 +14630,12 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1535114630 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {
1535214631 return ira->codegen->invalid_instruction;
1535314632 }
15354 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type))
15355 return nullptr;
14633 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) {
14634 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
14635 if (fn_entry == nullptr || fn_entry->inferred_async_node == nullptr) {
14636 return nullptr;
14637 }
14638 }
1535614639
1535714640 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);
1535814641 result_loc->written = true;
......@@ -15614,48 +14897,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
1561414897
1561514898static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
1561614899 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
15617 IrInstruction *async_allocator_inst)
14900 IrInstruction *casted_new_stack)
1561814901{
15619 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);
15620 ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base);
15621 ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type;
15622 IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, realloc_field_name, &call_instruction->base,
15623 async_allocator_inst, container_type, false);
15624 if (type_is_invalid(field_ptr_inst->value.type)) {
15625 return ira->codegen->invalid_instruction;
15626 }
15627 ZigType *ptr_to_realloc_fn_type = field_ptr_inst->value.type;
15628 ir_assert(ptr_to_realloc_fn_type->id == ZigTypeIdPointer, &call_instruction->base);
14902 if (casted_new_stack != nullptr) {
14903 // this is an @asyncCall
1562914904
15630 ZigType *realloc_fn_type = ptr_to_realloc_fn_type->data.pointer.child_type;
15631 if (realloc_fn_type->id != ZigTypeIdFn) {
15632 ir_add_error(ira, &call_instruction->base,
15633 buf_sprintf("expected reallocation function, found '%s'", buf_ptr(&realloc_fn_type->name)));
15634 return ira->codegen->invalid_instruction;
15635 }
14905 if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
14906 ir_add_error(ira, fn_ref,
14907 buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
14908 return ira->codegen->invalid_instruction;
14909 }
14910
14911 IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child;
14912 if (type_is_invalid(ret_ptr->value.type))
14913 return ira->codegen->invalid_instruction;
1563614914
15637 ZigType *realloc_fn_return_type = realloc_fn_type->data.fn.fn_type_id.return_type;
15638 if (realloc_fn_return_type->id != ZigTypeIdErrorUnion) {
15639 ir_add_error(ira, fn_ref,
15640 buf_sprintf("expected allocation function to return error union, but it returns '%s'", buf_ptr(&realloc_fn_return_type->name)));
14915 ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type);
14916
14917 IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
14918 arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type);
14919 return &call_gen->base;
14920 } else if (fn_entry == nullptr) {
14921 ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
1564114922 return ira->codegen->invalid_instruction;
1564214923 }
15643 ZigType *alloc_fn_error_set_type = realloc_fn_return_type->data.error_union.err_set_type;
15644 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
15645 ZigType *promise_type = get_promise_type(ira->codegen, return_type);
15646 ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
1564714924
15648 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(),
15649 async_return_type, nullptr, true, true, false);
14925 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry);
14926 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
14927 frame_type, nullptr, true, true, false);
1565014928 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
1565114929 return result_loc;
1565214930 }
15653
15654 return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
15655 casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc,
15656 async_return_type);
14931 result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
14932 if (type_is_invalid(result_loc->value.type))
14933 return ira->codegen->invalid_instruction;
14934 return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
14935 casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base;
1565714936}
15658
1565914937static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
1566014938 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
1566114939{
......@@ -16002,20 +15280,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1600215280 }
1600315281 return ira->codegen->invalid_instruction;
1600415282 }
16005 if (fn_type_id->cc == CallingConventionAsync && !call_instruction->is_async) {
16006 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("must use async keyword to call async function"));
16007 if (fn_proto_node) {
16008 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
16009 }
16010 return ira->codegen->invalid_instruction;
16011 }
16012 if (fn_type_id->cc != CallingConventionAsync && call_instruction->is_async) {
16013 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("cannot use async keyword to call non-async function"));
16014 if (fn_proto_node) {
16015 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
16016 }
16017 return ira->codegen->invalid_instruction;
16018 }
1601915283
1602015284
1602115285 if (fn_type_id->is_var_args) {
......@@ -16352,33 +15616,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1635215616 break;
1635315617 }
1635415618 }
16355 IrInstruction *async_allocator_inst = nullptr;
16356 if (call_instruction->is_async) {
16357 AstNode *async_allocator_type_node = fn_proto_node->data.fn_proto.async_allocator_type;
16358 if (async_allocator_type_node != nullptr) {
16359 ZigType *async_allocator_type = ir_analyze_type_expr(ira, impl_fn->child_scope, async_allocator_type_node);
16360 if (type_is_invalid(async_allocator_type))
16361 return ira->codegen->invalid_instruction;
16362 inst_fn_type_id.async_allocator_type = async_allocator_type;
16363 }
16364 IrInstruction *uncasted_async_allocator_inst;
16365 if (call_instruction->async_allocator == nullptr) {
16366 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
16367 ImplicitAllocatorIdLocalVar);
16368 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16369 return ira->codegen->invalid_instruction;
16370 } else {
16371 uncasted_async_allocator_inst = call_instruction->async_allocator->child;
16372 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16373 return ira->codegen->invalid_instruction;
16374 }
16375 if (inst_fn_type_id.async_allocator_type == nullptr) {
16376 inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
16377 }
16378 async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
16379 if (type_is_invalid(async_allocator_inst->value.type))
16380 return ira->codegen->invalid_instruction;
16381 }
1638215619
1638315620 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
1638415621 if (existing_entry) {
......@@ -16405,11 +15642,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1640515642 if (handle_is_ptr(impl_fn_type_id->return_type)) {
1640615643 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
1640715644 impl_fn_type_id->return_type, nullptr, true, true, false);
16408 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||
16409 instr_is_unreachable(result_loc)))
16410 {
16411 return result_loc;
16412 }
15645 if (result_loc != nullptr) {
15646 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
15647 return result_loc;
15648 }
15649 if (!handle_is_ptr(result_loc->value.type->data.pointer.child_type)) {
15650 ir_reset_result(call_instruction->result_loc);
15651 result_loc = nullptr;
15652 }
15653 }
1641315654 } else {
1641415655 result_loc = nullptr;
1641515656 }
......@@ -16421,17 +15662,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1642115662 size_t impl_param_count = impl_fn_type_id->param_count;
1642215663 if (call_instruction->is_async) {
1642315664 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
16424 fn_ref, casted_args, impl_param_count, async_allocator_inst);
15665 nullptr, casted_args, impl_param_count, casted_new_stack);
1642515666 return ir_finish_anal(ira, result);
1642615667 }
1642715668
16428 assert(async_allocator_inst == nullptr);
16429 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
15669 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15670 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15671 parent_fn_entry->inferred_async_fn = impl_fn;
15672 }
15673
15674 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
1643015675 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
16431 call_instruction->is_async, nullptr, casted_new_stack, result_loc,
15676 false, casted_new_stack, result_loc,
1643215677 impl_fn_type_id->return_type);
1643315678
16434 return ir_finish_anal(ira, new_call_instruction);
15679 parent_fn_entry->call_list.append(new_call_instruction);
15680
15681 return ir_finish_anal(ira, &new_call_instruction->base);
1643515682 }
1643615683
1643715684 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
......@@ -16473,20 +15720,56 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1647315720 IrInstruction *old_arg = call_instruction->args[call_i]->child;
1647415721 if (type_is_invalid(old_arg->value.type))
1647515722 return ira->codegen->invalid_instruction;
16476 IrInstruction *casted_arg;
16477 if (next_arg_index < src_param_count) {
16478 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
16479 if (type_is_invalid(param_type))
16480 return ira->codegen->invalid_instruction;
16481 casted_arg = ir_implicit_cast(ira, old_arg, param_type);
16482 if (type_is_invalid(casted_arg->value.type))
16483 return ira->codegen->invalid_instruction;
15723
15724 if (old_arg->value.type->id == ZigTypeIdArgTuple) {
15725 for (size_t arg_tuple_i = old_arg->value.data.x_arg_tuple.start_index;
15726 arg_tuple_i < old_arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
15727 {
15728 ZigVar *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
15729 if (arg_var == nullptr) {
15730 ir_add_error(ira, old_arg,
15731 buf_sprintf("compiler bug: var args can't handle void. https://github.com/ziglang/zig/issues/557"));
15732 return ira->codegen->invalid_instruction;
15733 }
15734 IrInstruction *arg_var_ptr_inst = ir_get_var_ptr(ira, old_arg, arg_var);
15735 if (type_is_invalid(arg_var_ptr_inst->value.type))
15736 return ira->codegen->invalid_instruction;
15737
15738 IrInstruction *arg_tuple_arg = ir_get_deref(ira, old_arg, arg_var_ptr_inst, nullptr);
15739 if (type_is_invalid(arg_tuple_arg->value.type))
15740 return ira->codegen->invalid_instruction;
15741
15742 IrInstruction *casted_arg;
15743 if (next_arg_index < src_param_count) {
15744 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
15745 if (type_is_invalid(param_type))
15746 return ira->codegen->invalid_instruction;
15747 casted_arg = ir_implicit_cast(ira, arg_tuple_arg, param_type);
15748 if (type_is_invalid(casted_arg->value.type))
15749 return ira->codegen->invalid_instruction;
15750 } else {
15751 casted_arg = arg_tuple_arg;
15752 }
15753
15754 casted_args[next_arg_index] = casted_arg;
15755 next_arg_index += 1;
15756 }
1648415757 } else {
16485 casted_arg = old_arg;
16486 }
15758 IrInstruction *casted_arg;
15759 if (next_arg_index < src_param_count) {
15760 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;
15761 if (type_is_invalid(param_type))
15762 return ira->codegen->invalid_instruction;
15763 casted_arg = ir_implicit_cast(ira, old_arg, param_type);
15764 if (type_is_invalid(casted_arg->value.type))
15765 return ira->codegen->invalid_instruction;
15766 } else {
15767 casted_arg = old_arg;
15768 }
1648715769
16488 casted_args[next_arg_index] = casted_arg;
16489 next_arg_index += 1;
15770 casted_args[next_arg_index] = casted_arg;
15771 next_arg_index += 1;
15772 }
1649015773 }
1649115774
1649215775 assert(next_arg_index == call_param_count);
......@@ -16495,49 +15778,45 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1649515778 if (type_is_invalid(return_type))
1649615779 return ira->codegen->invalid_instruction;
1649715780
16498 if (call_instruction->is_async) {
16499 IrInstruction *uncasted_async_allocator_inst;
16500 if (call_instruction->async_allocator == nullptr) {
16501 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
16502 ImplicitAllocatorIdLocalVar);
16503 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16504 return ira->codegen->invalid_instruction;
16505 } else {
16506 uncasted_async_allocator_inst = call_instruction->async_allocator->child;
16507 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
16508 return ira->codegen->invalid_instruction;
16509
16510 }
16511 IrInstruction *async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, fn_type_id->async_allocator_type);
16512 if (type_is_invalid(async_allocator_inst->value.type))
16513 return ira->codegen->invalid_instruction;
15781 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
15782 ir_add_error(ira, &call_instruction->base,
15783 buf_sprintf("no-inline call of inline function"));
15784 return ira->codegen->invalid_instruction;
15785 }
1651415786
15787 if (call_instruction->is_async) {
1651515788 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
16516 casted_args, call_param_count, async_allocator_inst);
15789 casted_args, call_param_count, casted_new_stack);
1651715790 return ir_finish_anal(ira, result);
1651815791 }
1651915792
16520 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
16521 ir_add_error(ira, &call_instruction->base,
16522 buf_sprintf("no-inline call of inline function"));
16523 return ira->codegen->invalid_instruction;
15793 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15794 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15795 parent_fn_entry->inferred_async_fn = fn_entry;
1652415796 }
1652515797
1652615798 IrInstruction *result_loc;
1652715799 if (handle_is_ptr(return_type)) {
1652815800 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
1652915801 return_type, nullptr, true, true, false);
16530 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
16531 return result_loc;
15802 if (result_loc != nullptr) {
15803 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
15804 return result_loc;
15805 }
15806 if (!handle_is_ptr(result_loc->value.type->data.pointer.child_type)) {
15807 ir_reset_result(call_instruction->result_loc);
15808 result_loc = nullptr;
15809 }
1653215810 }
1653315811 } else {
1653415812 result_loc = nullptr;
1653515813 }
1653615814
16537 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
16538 call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack,
15815 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
15816 call_param_count, casted_args, fn_inline, false, casted_new_stack,
1653915817 result_loc, return_type);
16540 return ir_finish_anal(ira, new_call_instruction);
15818 parent_fn_entry->call_list.append(new_call_instruction);
15819 return ir_finish_anal(ira, &new_call_instruction->base);
1654115820}
1654215821
1654315822static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {
......@@ -16682,7 +15961,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
1668215961 zig_unreachable();
1668315962}
1668415963
16685static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
15964static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
1668615965 Error err;
1668715966 IrInstruction *value = un_op_instruction->value->child;
1668815967 ZigType *type_entry = ir_resolve_type(ira, value);
......@@ -16716,8 +15995,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
1671615995 case ZigTypeIdFn:
1671715996 case ZigTypeIdBoundFn:
1671815997 case ZigTypeIdArgTuple:
16719 case ZigTypeIdPromise:
15998 case ZigTypeIdFnFrame:
15999 case ZigTypeIdAnyFrame:
1672016000 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));
16001
1672116002 case ZigTypeIdUnreachable:
1672216003 case ZigTypeIdOpaque:
1672316004 ir_add_error_node(ira, un_op_instruction->base.source_node,
......@@ -16881,7 +16162,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
1688116162 return result;
1688216163 }
1688316164 case IrUnOpOptional:
16884 return ir_analyze_maybe(ira, instruction);
16165 return ir_analyze_optional_type(ira, instruction);
1688516166 }
1688616167 zig_unreachable();
1688716168}
......@@ -18441,6 +17722,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
1844117722 return ir_const_void(ira, &instruction->base);
1844217723}
1844317724
17725static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira,
17726 IrInstructionAnyFrameType *instruction)
17727{
17728 ZigType *payload_type = nullptr;
17729 if (instruction->payload_type != nullptr) {
17730 payload_type = ir_resolve_type(ira, instruction->payload_type->child);
17731 if (type_is_invalid(payload_type))
17732 return ira->codegen->invalid_instruction;
17733 }
17734
17735 ZigType *any_frame_type = get_any_frame_type(ira->codegen, payload_type);
17736 return ir_const_type(ira, &instruction->base, any_frame_type);
17737}
17738
1844417739static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1844517740 IrInstructionSliceType *slice_type_instruction)
1844617741{
......@@ -18488,8 +17783,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1848817783 case ZigTypeIdUnion:
1848917784 case ZigTypeIdFn:
1849017785 case ZigTypeIdBoundFn:
18491 case ZigTypeIdPromise:
1849217786 case ZigTypeIdVector:
17787 case ZigTypeIdFnFrame:
17788 case ZigTypeIdAnyFrame:
1849317789 {
1849417790 ResolveStatus needed_status = (align_bytes == 0) ?
1849517791 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
......@@ -18603,8 +17899,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
1860317899 case ZigTypeIdUnion:
1860417900 case ZigTypeIdFn:
1860517901 case ZigTypeIdBoundFn:
18606 case ZigTypeIdPromise:
1860717902 case ZigTypeIdVector:
17903 case ZigTypeIdFnFrame:
17904 case ZigTypeIdAnyFrame:
1860817905 {
1860917906 if ((err = ensure_complete_type(ira->codegen, child_type)))
1861017907 return ira->codegen->invalid_instruction;
......@@ -18615,22 +17912,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
1861517912 zig_unreachable();
1861617913}
1861717914
18618static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInstructionPromiseType *instruction) {
18619 ZigType *promise_type;
18620
18621 if (instruction->payload_type == nullptr) {
18622 promise_type = ira->codegen->builtin_types.entry_promise;
18623 } else {
18624 ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child);
18625 if (type_is_invalid(payload_type))
18626 return ira->codegen->invalid_instruction;
18627
18628 promise_type = get_promise_type(ira->codegen, payload_type);
18629 }
18630
18631 return ir_const_type(ira, &instruction->base, promise_type);
18632}
18633
1863417915static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
1863517916 IrInstructionSizeOf *size_of_instruction)
1863617917{
......@@ -18670,8 +17951,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
1867017951 case ZigTypeIdEnum:
1867117952 case ZigTypeIdUnion:
1867217953 case ZigTypeIdFn:
18673 case ZigTypeIdPromise:
1867417954 case ZigTypeIdVector:
17955 case ZigTypeIdFnFrame:
17956 case ZigTypeIdAnyFrame:
1867517957 {
1867617958 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
1867717959 return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);
......@@ -19157,7 +18439,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1915718439 case ZigTypeIdComptimeInt:
1915818440 case ZigTypeIdEnumLiteral:
1915918441 case ZigTypeIdPointer:
19160 case ZigTypeIdPromise:
1916118442 case ZigTypeIdFn:
1916218443 case ZigTypeIdErrorSet: {
1916318444 if (pointee_val) {
......@@ -19236,6 +18517,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1923618517 case ZigTypeIdArgTuple:
1923718518 case ZigTypeIdOpaque:
1923818519 case ZigTypeIdVector:
18520 case ZigTypeIdFnFrame:
18521 case ZigTypeIdAnyFrame:
1923918522 ir_add_error(ira, &switch_target_instruction->base,
1924018523 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
1924118524 return ira->codegen->invalid_instruction;
......@@ -20670,32 +19953,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2067019953
2067119954 break;
2067219955 }
20673 case ZigTypeIdPromise:
20674 {
20675 result = create_const_vals(1);
20676 result->special = ConstValSpecialStatic;
20677 result->type = ir_type_info_get_type(ira, "Promise", nullptr);
20678
20679 ConstExprValue *fields = create_const_vals(1);
20680 result->data.x_struct.fields = fields;
20681
20682 // child: ?type
20683 ensure_field_index(result->type, "child", 0);
20684 fields[0].special = ConstValSpecialStatic;
20685 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
19956 case ZigTypeIdAnyFrame: {
19957 result = create_const_vals(1);
19958 result->special = ConstValSpecialStatic;
19959 result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr);
2068619960
20687 if (type_entry->data.promise.result_type == nullptr)
20688 fields[0].data.x_optional = nullptr;
20689 else {
20690 ConstExprValue *child_type = create_const_vals(1);
20691 child_type->special = ConstValSpecialStatic;
20692 child_type->type = ira->codegen->builtin_types.entry_type;
20693 child_type->data.x_type = type_entry->data.promise.result_type;
20694 fields[0].data.x_optional = child_type;
20695 }
19961 ConstExprValue *fields = create_const_vals(1);
19962 result->data.x_struct.fields = fields;
2069619963
20697 break;
20698 }
19964 // child: ?type
19965 ensure_field_index(result->type, "child", 0);
19966 fields[0].special = ConstValSpecialStatic;
19967 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
19968 fields[0].data.x_optional = (type_entry->data.any_frame.result_type == nullptr) ? nullptr :
19969 create_const_type(ira->codegen, type_entry->data.any_frame.result_type);
19970 break;
19971 }
2069919972 case ZigTypeIdEnum:
2070019973 {
2070119974 result = create_const_vals(1);
......@@ -21005,7 +20278,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2100520278 result->special = ConstValSpecialStatic;
2100620279 result->type = ir_type_info_get_type(ira, "Fn", nullptr);
2100720280
21008 ConstExprValue *fields = create_const_vals(6);
20281 ConstExprValue *fields = create_const_vals(5);
2100920282 result->data.x_struct.fields = fields;
2101020283
2101120284 // calling_convention: TypeInfo.CallingConvention
......@@ -21038,19 +20311,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2103820311 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
2103920312 fields[3].data.x_optional = return_type;
2104020313 }
21041 // async_allocator_type: type
21042 ensure_field_index(result->type, "async_allocator_type", 4);
21043 fields[4].special = ConstValSpecialStatic;
21044 fields[4].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
21045 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
21046 fields[4].data.x_optional = nullptr;
21047 else {
21048 ConstExprValue *async_alloc_type = create_const_vals(1);
21049 async_alloc_type->special = ConstValSpecialStatic;
21050 async_alloc_type->type = ira->codegen->builtin_types.entry_type;
21051 async_alloc_type->data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
21052 fields[4].data.x_optional = async_alloc_type;
21053 }
2105420314 // args: []TypeInfo.FnArg
2105520315 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);
2105620316 if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) {
......@@ -21065,10 +20325,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2106520325 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
2106620326 fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
2106720327
21068 init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
20328 init_const_slice(ira->codegen, &fields[4], fn_arg_array, 0, fn_arg_count, false);
2106920329
21070 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++)
21071 {
20330 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
2107220331 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
2107320332 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index];
2107420333
......@@ -21115,6 +20374,8 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2111520374
2111620375 break;
2111720376 }
20377 case ZigTypeIdFnFrame:
20378 zig_panic("TODO @typeInfo for async function frames");
2111820379 }
2111920380
2112020381 assert(result != nullptr);
......@@ -21312,12 +20573,15 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
2131220573 }
2131320574 for (size_t i = 0; i < errors_len; i += 1) {
2131420575 Stage2ErrorMsg *clang_err = &errors_ptr[i];
21315 ErrorMsg *err_msg = err_msg_create_with_offset(
21316 clang_err->filename_ptr ?
21317 buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
21318 clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
21319 buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
21320 err_msg_add_note(parent_err_msg, err_msg);
20576 // Clang can emit "too many errors, stopping now", in which case `source` and `filename_ptr` are null
20577 if (clang_err->source && clang_err->filename_ptr) {
20578 ErrorMsg *err_msg = err_msg_create_with_offset(
20579 clang_err->filename_ptr ?
20580 buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
20581 clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
20582 buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
20583 err_msg_add_note(parent_err_msg, err_msg);
20584 }
2132120585 }
2132220586
2132320587 return ira->codegen->invalid_instruction;
......@@ -22825,11 +22089,51 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns
2282522089 return result;
2282622090}
2282722091
22828static IrInstruction *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructionHandle *instruction) {
22092static IrInstruction *ir_analyze_instruction_frame_handle(IrAnalyze *ira, IrInstructionFrameHandle *instruction) {
22093 ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
22094 ir_assert(fn != nullptr, &instruction->base);
22095
22096 if (fn->inferred_async_node == nullptr) {
22097 fn->inferred_async_node = instruction->base.source_node;
22098 }
22099
22100 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn);
22101 ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false);
22102
2282922103 IrInstruction *result = ir_build_handle(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
22830 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
22831 assert(fn_entry != nullptr);
22832 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
22104 result->value.type = ptr_frame_type;
22105 return result;
22106}
22107
22108static IrInstruction *ir_analyze_instruction_frame_type(IrAnalyze *ira, IrInstructionFrameType *instruction) {
22109 ZigFn *fn = ir_resolve_fn(ira, instruction->fn->child);
22110 if (fn == nullptr)
22111 return ira->codegen->invalid_instruction;
22112
22113 if (fn->type_entry->data.fn.is_generic) {
22114 ir_add_error(ira, &instruction->base,
22115 buf_sprintf("@Frame() of generic function"));
22116 return ira->codegen->invalid_instruction;
22117 }
22118
22119 ZigType *ty = get_fn_frame_type(ira->codegen, fn);
22120 return ir_const_type(ira, &instruction->base, ty);
22121}
22122
22123static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstructionFrameSizeSrc *instruction) {
22124 IrInstruction *fn = instruction->fn->child;
22125 if (type_is_invalid(fn->value.type))
22126 return ira->codegen->invalid_instruction;
22127
22128 if (fn->value.type->id != ZigTypeIdFn) {
22129 ir_add_error(ira, fn,
22130 buf_sprintf("expected function, found '%s'", buf_ptr(&fn->value.type->name)));
22131 return ira->codegen->invalid_instruction;
22132 }
22133
22134 IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope,
22135 instruction->base.source_node, fn);
22136 result->value.type = ira->codegen->builtin_types.entry_usize;
2283322137 return result;
2283422138}
2283522139
......@@ -22864,7 +22168,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2286422168 case ZigTypeIdInt:
2286522169 case ZigTypeIdFloat:
2286622170 case ZigTypeIdPointer:
22867 case ZigTypeIdPromise:
2286822171 case ZigTypeIdArray:
2286922172 case ZigTypeIdStruct:
2287022173 case ZigTypeIdOptional:
......@@ -22874,6 +22177,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2287422177 case ZigTypeIdUnion:
2287522178 case ZigTypeIdFn:
2287622179 case ZigTypeIdVector:
22180 case ZigTypeIdFnFrame:
22181 case ZigTypeIdAnyFrame:
2287722182 {
2287822183 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
2287922184 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
......@@ -22988,19 +22293,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
2298822293 return result;
2298922294}
2299022295
22991static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstructionResultPtr *instruction) {
22992 IrInstruction *result = instruction->result->child;
22993 if (type_is_invalid(result->value.type))
22994 return result;
22995
22996 if (instruction->result_loc->written && instruction->result_loc->resolved_loc != nullptr &&
22997 !instr_is_comptime(result))
22998 {
22999 return instruction->result_loc->resolved_loc;
23000 }
23001 return ir_get_ref(ira, &instruction->base, result, true, false);
23002}
23003
2300422296static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,
2300522297 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {
2300622298 if (float_type->id == ZigTypeIdComptimeFloat) {
......@@ -23125,11 +22417,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
2312522417 if (type_is_invalid(base_ptr->value.type))
2312622418 return ira->codegen->invalid_instruction;
2312722419
23128 IrInstruction *value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr);
22420 IrInstruction *value;
22421 if (instruction->base_ptr_is_payload) {
22422 value = base_ptr;
22423 } else {
22424 value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr);
22425 }
22426
2312922427 ZigType *type_entry = value->value.type;
2313022428 if (type_is_invalid(type_entry))
2313122429 return ira->codegen->invalid_instruction;
23132
2313322430 if (type_entry->id == ZigTypeIdErrorUnion) {
2313422431 if (instr_is_comptime(value)) {
2313522432 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
......@@ -23423,18 +22720,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
2342322720 return ira->codegen->invalid_instruction;
2342422721 }
2342522722
23426 if (fn_type_id.cc == CallingConventionAsync) {
23427 if (instruction->async_allocator_type_value == nullptr) {
23428 ir_add_error(ira, &instruction->base,
23429 buf_sprintf("async fn proto missing allocator type"));
23430 return ira->codegen->invalid_instruction;
23431 }
23432 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child;
23433 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
23434 if (type_is_invalid(fn_type_id.async_allocator_type))
23435 return ira->codegen->invalid_instruction;
23436 }
23437
2343822723 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
2343922724}
2344022725
......@@ -23673,7 +22958,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
2367322958 if (type_is_invalid(statement_type))
2367422959 return ira->codegen->invalid_instruction;
2367522960
23676 if (statement_type->id != ZigTypeIdVoid) {
22961 if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) {
2367722962 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
2367822963 }
2367922964
......@@ -23928,7 +23213,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2392823213 case ZigTypeIdEnumLiteral:
2392923214 case ZigTypeIdUndefined:
2393023215 case ZigTypeIdNull:
23931 case ZigTypeIdPromise:
2393223216 case ZigTypeIdErrorUnion:
2393323217 case ZigTypeIdErrorSet:
2393423218 zig_unreachable();
......@@ -24038,6 +23322,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2403823322 zig_panic("TODO buf_write_value_bytes fn type");
2403923323 case ZigTypeIdUnion:
2404023324 zig_panic("TODO buf_write_value_bytes union type");
23325 case ZigTypeIdFnFrame:
23326 zig_panic("TODO buf_write_value_bytes async fn frame type");
23327 case ZigTypeIdAnyFrame:
23328 zig_panic("TODO buf_write_value_bytes anyframe type");
2404123329 }
2404223330 zig_unreachable();
2404323331}
......@@ -24082,7 +23370,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
2408223370 case ZigTypeIdEnumLiteral:
2408323371 case ZigTypeIdUndefined:
2408423372 case ZigTypeIdNull:
24085 case ZigTypeIdPromise:
2408623373 zig_unreachable();
2408723374 case ZigTypeIdVoid:
2408823375 return ErrorNone;
......@@ -24218,6 +23505,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
2421823505 zig_panic("TODO buf_read_value_bytes fn type");
2421923506 case ZigTypeIdUnion:
2422023507 zig_panic("TODO buf_read_value_bytes union type");
23508 case ZigTypeIdFnFrame:
23509 zig_panic("TODO buf_read_value_bytes async fn frame type");
23510 case ZigTypeIdAnyFrame:
23511 zig_panic("TODO buf_read_value_bytes anyframe type");
2422123512 }
2422223513 zig_unreachable();
2422323514}
......@@ -24568,184 +23859,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2456823859 }
2456923860}
2457023861
24571static IrInstruction *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
24572 IrInstruction *target_inst = instruction->target->child;
24573 if (type_is_invalid(target_inst->value.type))
24574 return ira->codegen->invalid_instruction;
24575 IrInstruction *casted_target = ir_implicit_cast(ira, target_inst, ira->codegen->builtin_types.entry_promise);
24576 if (type_is_invalid(casted_target->value.type))
24577 return ira->codegen->invalid_instruction;
24578
24579 IrInstruction *result = ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_target);
24580 result->value.type = ira->codegen->builtin_types.entry_void;
24581 result->value.special = ConstValSpecialStatic;
24582 return result;
24583}
24584
24585static IrInstruction *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) {
24586 IrInstruction *promise_ptr = instruction->promise_ptr->child;
24587 if (type_is_invalid(promise_ptr->value.type))
24588 return ira->codegen->invalid_instruction;
24589
24590 IrInstruction *result = ir_build_coro_id(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24591 promise_ptr);
24592 result->value.type = ira->codegen->builtin_types.entry_usize;
24593 return result;
24594}
24595
24596static IrInstruction *ir_analyze_instruction_coro_alloc(IrAnalyze *ira, IrInstructionCoroAlloc *instruction) {
24597 IrInstruction *coro_id = instruction->coro_id->child;
24598 if (type_is_invalid(coro_id->value.type))
24599 return ira->codegen->invalid_instruction;
24600
24601 IrInstruction *result = ir_build_coro_alloc(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24602 coro_id);
24603 result->value.type = ira->codegen->builtin_types.entry_bool;
24604 return result;
24605}
24606
24607static IrInstruction *ir_analyze_instruction_coro_size(IrAnalyze *ira, IrInstructionCoroSize *instruction) {
24608 IrInstruction *result = ir_build_coro_size(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
24609 result->value.type = ira->codegen->builtin_types.entry_usize;
24610 return result;
24611}
24612
24613static IrInstruction *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstructionCoroBegin *instruction) {
24614 IrInstruction *coro_id = instruction->coro_id->child;
24615 if (type_is_invalid(coro_id->value.type))
24616 return ira->codegen->invalid_instruction;
24617
24618 IrInstruction *coro_mem_ptr = instruction->coro_mem_ptr->child;
24619 if (type_is_invalid(coro_mem_ptr->value.type))
24620 return ira->codegen->invalid_instruction;
24621
24622 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24623 ir_assert(fn_entry != nullptr, &instruction->base);
24624 IrInstruction *result = ir_build_coro_begin(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24625 coro_id, coro_mem_ptr);
24626 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
24627 return result;
24628}
24629
24630static IrInstruction *ir_analyze_instruction_get_implicit_allocator(IrAnalyze *ira, IrInstructionGetImplicitAllocator *instruction) {
24631 return ir_get_implicit_allocator(ira, &instruction->base, instruction->id);
24632}
24633
24634static IrInstruction *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, IrInstructionCoroAllocFail *instruction) {
24635 IrInstruction *err_val = instruction->err_val->child;
24636 if (type_is_invalid(err_val->value.type))
24637 return ir_unreach_error(ira);
24638
24639 IrInstruction *result = ir_build_coro_alloc_fail(&ira->new_irb, instruction->base.scope, instruction->base.source_node, err_val);
24640 result->value.type = ira->codegen->builtin_types.entry_unreachable;
24641 return ir_finish_anal(ira, result);
24642}
24643
24644static IrInstruction *ir_analyze_instruction_coro_suspend(IrAnalyze *ira, IrInstructionCoroSuspend *instruction) {
24645 IrInstruction *save_point = nullptr;
24646 if (instruction->save_point != nullptr) {
24647 save_point = instruction->save_point->child;
24648 if (type_is_invalid(save_point->value.type))
24649 return ira->codegen->invalid_instruction;
24650 }
24651
24652 IrInstruction *is_final = instruction->is_final->child;
24653 if (type_is_invalid(is_final->value.type))
24654 return ira->codegen->invalid_instruction;
24655
24656 IrInstruction *result = ir_build_coro_suspend(&ira->new_irb, instruction->base.scope,
24657 instruction->base.source_node, save_point, is_final);
24658 result->value.type = ira->codegen->builtin_types.entry_u8;
24659 return result;
24660}
24661
24662static IrInstruction *ir_analyze_instruction_coro_end(IrAnalyze *ira, IrInstructionCoroEnd *instruction) {
24663 IrInstruction *result = ir_build_coro_end(&ira->new_irb, instruction->base.scope,
24664 instruction->base.source_node);
24665 result->value.type = ira->codegen->builtin_types.entry_void;
24666 return result;
24667}
24668
24669static IrInstruction *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstructionCoroFree *instruction) {
24670 IrInstruction *coro_id = instruction->coro_id->child;
24671 if (type_is_invalid(coro_id->value.type))
24672 return ira->codegen->invalid_instruction;
24673
24674 IrInstruction *coro_handle = instruction->coro_handle->child;
24675 if (type_is_invalid(coro_handle->value.type))
24676 return ira->codegen->invalid_instruction;
24677
24678 IrInstruction *result = ir_build_coro_free(&ira->new_irb, instruction->base.scope,
24679 instruction->base.source_node, coro_id, coro_handle);
24680 ZigType *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
24681 result->value.type = get_optional_type(ira->codegen, ptr_type);
24682 return result;
24683}
24684
24685static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {
24686 IrInstruction *awaiter_handle = instruction->awaiter_handle->child;
24687 if (type_is_invalid(awaiter_handle->value.type))
24688 return ira->codegen->invalid_instruction;
24689
24690 IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise);
24691 if (type_is_invalid(casted_target->value.type))
24692 return ira->codegen->invalid_instruction;
24693
24694 IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope,
24695 instruction->base.source_node, casted_target);
24696 result->value.type = ira->codegen->builtin_types.entry_void;
24697 return result;
24698}
24699
24700static IrInstruction *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstructionCoroSave *instruction) {
24701 IrInstruction *coro_handle = instruction->coro_handle->child;
24702 if (type_is_invalid(coro_handle->value.type))
24703 return ira->codegen->invalid_instruction;
24704
24705 IrInstruction *result = ir_build_coro_save(&ira->new_irb, instruction->base.scope,
24706 instruction->base.source_node, coro_handle);
24707 result->value.type = ira->codegen->builtin_types.entry_usize;
24708 return result;
24709}
24710
24711static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInstructionCoroPromise *instruction) {
24712 IrInstruction *coro_handle = instruction->coro_handle->child;
24713 if (type_is_invalid(coro_handle->value.type))
24714 return ira->codegen->invalid_instruction;
24715
24716 if (coro_handle->value.type->id != ZigTypeIdPromise ||
24717 coro_handle->value.type->data.promise.result_type == nullptr)
24718 {
24719 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
24720 buf_ptr(&coro_handle->value.type->name)));
24721 return ira->codegen->invalid_instruction;
24722 }
24723
24724 ZigType *coro_frame_type = get_promise_frame_type(ira->codegen,
24725 coro_handle->value.type->data.promise.result_type);
24726
24727 IrInstruction *result = ir_build_coro_promise(&ira->new_irb, instruction->base.scope,
24728 instruction->base.source_node, coro_handle);
24729 result->value.type = get_pointer_to_type(ira->codegen, coro_frame_type, false);
24730 return result;
24731}
24732
24733static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {
24734 IrInstruction *realloc_fn = instruction->realloc_fn->child;
24735 if (type_is_invalid(realloc_fn->value.type))
24736 return ira->codegen->invalid_instruction;
24737
24738 IrInstruction *coro_size = instruction->coro_size->child;
24739 if (type_is_invalid(coro_size->value.type))
24740 return ira->codegen->invalid_instruction;
24741
24742 IrInstruction *result = ir_build_coro_alloc_helper(&ira->new_irb, instruction->base.scope,
24743 instruction->base.source_node, realloc_fn, coro_size);
24744 ZigType *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
24745 result->value.type = get_optional_type(ira->codegen, u8_ptr_type);
24746 return result;
24747}
24748
2474923862static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
2475023863 ZigType *operand_type = ir_resolve_type(ira, op);
2475123864 if (type_is_invalid(operand_type))
......@@ -24877,65 +23990,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
2487723990 return result;
2487823991}
2487923992
24880static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
24881 ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child);
24882 if (type_is_invalid(promise_type))
24883 return ira->codegen->invalid_instruction;
24884
24885 if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) {
24886 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
24887 buf_ptr(&promise_type->name)));
24888 return ira->codegen->invalid_instruction;
24889 }
24890
24891 return ir_const_type(ira, &instruction->base, promise_type->data.promise.result_type);
24892}
24893
24894static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) {
24895 ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child);
24896 if (type_is_invalid(promise_result_type))
24897 return ira->codegen->invalid_instruction;
24898
24899 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24900 ir_assert(fn_entry != nullptr, &instruction->base);
24901
24902 if (type_can_fail(promise_result_type)) {
24903 fn_entry->calls_or_awaits_errorable_fn = true;
24904 }
24905
24906 return ir_const_void(ira, &instruction->base);
24907}
24908
24909static IrInstruction *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
24910 IrInstructionMergeErrRetTraces *instruction)
24911{
24912 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->child;
24913 if (type_is_invalid(coro_promise_ptr->value.type))
24914 return ira->codegen->invalid_instruction;
24915
24916 ir_assert(coro_promise_ptr->value.type->id == ZigTypeIdPointer, &instruction->base);
24917 ZigType *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
24918 ir_assert(promise_frame_type->id == ZigTypeIdStruct, &instruction->base);
24919 ZigType *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
24920
24921 if (!type_can_fail(promise_result_type)) {
24922 return ir_const_void(ira, &instruction->base);
24923 }
24924
24925 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->child;
24926 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
24927 return ira->codegen->invalid_instruction;
24928
24929 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->child;
24930 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
24931 return ira->codegen->invalid_instruction;
24932
24933 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
24934 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
24935 result->value.type = ira->codegen->builtin_types.entry_void;
24936 return result;
24937}
24938
2493923993static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
2494023994 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
2494123995 instruction->base.source_node);
......@@ -24943,17 +23997,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I
2494323997 return result;
2494423998}
2494523999
24946static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
24947 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->child;
24948 if (type_is_invalid(err_ret_trace_ptr->value.type))
24949 return ira->codegen->invalid_instruction;
24950
24951 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
24952 instruction->base.source_node, err_ret_trace_ptr);
24953 result->value.type = ira->codegen->builtin_types.entry_void;
24954 return result;
24955}
24956
2495724000static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
2495824001 ConstExprValue *op, ConstExprValue *out_val) {
2495924002 assert(ira && source_instr && float_type && out_val && op);
......@@ -25480,6 +24523,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i
2548024523 union_type, field_name, field_result_loc, result_loc);
2548124524}
2548224525
24526static IrInstruction *ir_analyze_instruction_suspend_begin(IrAnalyze *ira, IrInstructionSuspendBegin *instruction) {
24527 IrInstructionSuspendBegin *result = ir_build_suspend_begin(&ira->new_irb, instruction->base.scope,
24528 instruction->base.source_node);
24529 return &result->base;
24530}
24531
24532static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,
24533 IrInstructionSuspendFinish *instruction)
24534{
24535 IrInstruction *begin_base = instruction->begin->base.child;
24536 if (type_is_invalid(begin_base->value.type))
24537 return ira->codegen->invalid_instruction;
24538 ir_assert(begin_base->id == IrInstructionIdSuspendBegin, &instruction->base);
24539 IrInstructionSuspendBegin *begin = reinterpret_cast<IrInstructionSuspendBegin *>(begin_base);
24540
24541 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24542 ir_assert(fn_entry != nullptr, &instruction->base);
24543
24544 if (fn_entry->inferred_async_node == nullptr) {
24545 fn_entry->inferred_async_node = instruction->base.source_node;
24546 }
24547
24548 return ir_build_suspend_finish(&ira->new_irb, instruction->base.scope, instruction->base.source_node, begin);
24549}
24550
24551static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruction *source_instr,
24552 IrInstruction *frame_ptr)
24553{
24554 if (type_is_invalid(frame_ptr->value.type))
24555 return ira->codegen->invalid_instruction;
24556
24557 ZigType *result_type;
24558 IrInstruction *frame;
24559 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24560 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24561 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24562 {
24563 result_type = frame_ptr->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;
24564 frame = frame_ptr;
24565 } else {
24566 frame = ir_get_deref(ira, source_instr, frame_ptr, nullptr);
24567 if (frame->value.type->id == ZigTypeIdPointer &&
24568 frame->value.type->data.pointer.ptr_len == PtrLenSingle &&
24569 frame->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24570 {
24571 result_type = frame->value.type->data.pointer.child_type->data.frame.fn->type_entry->data.fn.fn_type_id.return_type;
24572 } else if (frame->value.type->id != ZigTypeIdAnyFrame ||
24573 frame->value.type->data.any_frame.result_type == nullptr)
24574 {
24575 ir_add_error(ira, source_instr,
24576 buf_sprintf("expected anyframe->T, found '%s'", buf_ptr(&frame->value.type->name)));
24577 return ira->codegen->invalid_instruction;
24578 } else {
24579 result_type = frame->value.type->data.any_frame.result_type;
24580 }
24581 }
24582
24583 ZigType *any_frame_type = get_any_frame_type(ira->codegen, result_type);
24584 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24585 if (type_is_invalid(casted_frame->value.type))
24586 return ira->codegen->invalid_instruction;
24587
24588 return casted_frame;
24589}
24590
24591static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {
24592 IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child);
24593 if (type_is_invalid(frame->value.type))
24594 return ira->codegen->invalid_instruction;
24595
24596 ZigType *result_type = frame->value.type->data.any_frame.result_type;
24597
24598 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24599 ir_assert(fn_entry != nullptr, &instruction->base);
24600
24601 if (fn_entry->inferred_async_node == nullptr) {
24602 fn_entry->inferred_async_node = instruction->base.source_node;
24603 }
24604
24605 if (type_can_fail(result_type)) {
24606 fn_entry->calls_or_awaits_errorable_fn = true;
24607 }
24608
24609 IrInstruction *result_loc;
24610 if (type_has_bits(result_type)) {
24611 result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
24612 result_type, nullptr, true, true, true);
24613 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
24614 return result_loc;
24615 } else {
24616 result_loc = nullptr;
24617 }
24618
24619 IrInstruction *result = ir_build_await_gen(ira, &instruction->base, frame, result_type, result_loc);
24620 return ir_finish_anal(ira, result);
24621}
24622
24623static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructionResume *instruction) {
24624 IrInstruction *frame_ptr = instruction->frame->child;
24625 if (type_is_invalid(frame_ptr->value.type))
24626 return ira->codegen->invalid_instruction;
24627
24628 IrInstruction *frame;
24629 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24630 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24631 frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
24632 {
24633 frame = frame_ptr;
24634 } else {
24635 frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr);
24636 }
24637
24638 ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr);
24639 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24640 if (type_is_invalid(casted_frame->value.type))
24641 return ira->codegen->invalid_instruction;
24642
24643 return ir_build_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame);
24644}
24645
24646static IrInstruction *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstructionSpillBegin *instruction) {
24647 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope))
24648 return ir_const_void(ira, &instruction->base);
24649
24650 IrInstruction *operand = instruction->operand->child;
24651 if (type_is_invalid(operand->value.type))
24652 return ira->codegen->invalid_instruction;
24653
24654 if (!type_has_bits(operand->value.type))
24655 return ir_const_void(ira, &instruction->base);
24656
24657 ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base);
24658 ira->new_irb.exec->need_err_code_spill = true;
24659
24660 IrInstructionSpillBegin *result = ir_build_spill_begin(&ira->new_irb, instruction->base.scope,
24661 instruction->base.source_node, operand, instruction->spill_id);
24662 return &result->base;
24663}
24664
24665static IrInstruction *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstructionSpillEnd *instruction) {
24666 IrInstruction *operand = instruction->begin->operand->child;
24667 if (type_is_invalid(operand->value.type))
24668 return ira->codegen->invalid_instruction;
24669
24670 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope) || !type_has_bits(operand->value.type))
24671 return operand;
24672
24673 ir_assert(instruction->begin->base.child->id == IrInstructionIdSpillBegin, &instruction->base);
24674 IrInstructionSpillBegin *begin = reinterpret_cast<IrInstructionSpillBegin *>(instruction->begin->base.child);
24675
24676 IrInstruction *result = ir_build_spill_end(&ira->new_irb, instruction->base.scope,
24677 instruction->base.source_node, begin);
24678 result->value.type = operand->value.type;
24679 return result;
24680}
24681
2548324682static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
2548424683 switch (instruction->id) {
2548524684 case IrInstructionIdInvalid:
......@@ -25507,6 +24706,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2550724706 case IrInstructionIdSliceGen:
2550824707 case IrInstructionIdRefGen:
2550924708 case IrInstructionIdTestErrGen:
24709 case IrInstructionIdFrameSizeGen:
24710 case IrInstructionIdAwaitGen:
2551024711 zig_unreachable();
2551124712
2551224713 case IrInstructionIdReturn:
......@@ -25547,6 +24748,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2554724748 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);
2554824749 case IrInstructionIdSetFloatMode:
2554924750 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);
24751 case IrInstructionIdAnyFrameType:
24752 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
2555024753 case IrInstructionIdSliceType:
2555124754 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
2555224755 case IrInstructionIdGlobalAsm:
......@@ -25555,8 +24758,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2555524758 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
2555624759 case IrInstructionIdArrayType:
2555724760 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
25558 case IrInstructionIdPromiseType:
25559 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
2556024761 case IrInstructionIdSizeOf:
2556124762 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
2556224763 case IrInstructionIdTestNonNull:
......@@ -25655,8 +24856,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2565524856 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
2565624857 case IrInstructionIdFrameAddress:
2565724858 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
25658 case IrInstructionIdHandle:
25659 return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);
24859 case IrInstructionIdFrameHandle:
24860 return ir_analyze_instruction_frame_handle(ira, (IrInstructionFrameHandle *)instruction);
24861 case IrInstructionIdFrameType:
24862 return ir_analyze_instruction_frame_type(ira, (IrInstructionFrameType *)instruction);
24863 case IrInstructionIdFrameSizeSrc:
24864 return ir_analyze_instruction_frame_size(ira, (IrInstructionFrameSizeSrc *)instruction);
2566024865 case IrInstructionIdAlignOf:
2566124866 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
2566224867 case IrInstructionIdOverflowOp:
......@@ -25711,8 +24916,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2571124916 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);
2571224917 case IrInstructionIdResetResult:
2571324918 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);
25714 case IrInstructionIdResultPtr:
25715 return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction);
2571624919 case IrInstructionIdOpaqueType:
2571724920 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
2571824921 case IrInstructionIdSetAlignStack:
......@@ -25727,50 +24930,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2572724930 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
2572824931 case IrInstructionIdErrorUnion:
2572924932 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
25730 case IrInstructionIdCancel:
25731 return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction);
25732 case IrInstructionIdCoroId:
25733 return ir_analyze_instruction_coro_id(ira, (IrInstructionCoroId *)instruction);
25734 case IrInstructionIdCoroAlloc:
25735 return ir_analyze_instruction_coro_alloc(ira, (IrInstructionCoroAlloc *)instruction);
25736 case IrInstructionIdCoroSize:
25737 return ir_analyze_instruction_coro_size(ira, (IrInstructionCoroSize *)instruction);
25738 case IrInstructionIdCoroBegin:
25739 return ir_analyze_instruction_coro_begin(ira, (IrInstructionCoroBegin *)instruction);
25740 case IrInstructionIdGetImplicitAllocator:
25741 return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction);
25742 case IrInstructionIdCoroAllocFail:
25743 return ir_analyze_instruction_coro_alloc_fail(ira, (IrInstructionCoroAllocFail *)instruction);
25744 case IrInstructionIdCoroSuspend:
25745 return ir_analyze_instruction_coro_suspend(ira, (IrInstructionCoroSuspend *)instruction);
25746 case IrInstructionIdCoroEnd:
25747 return ir_analyze_instruction_coro_end(ira, (IrInstructionCoroEnd *)instruction);
25748 case IrInstructionIdCoroFree:
25749 return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction);
25750 case IrInstructionIdCoroResume:
25751 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
25752 case IrInstructionIdCoroSave:
25753 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
25754 case IrInstructionIdCoroPromise:
25755 return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction);
25756 case IrInstructionIdCoroAllocHelper:
25757 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
2575824933 case IrInstructionIdAtomicRmw:
2575924934 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
2576024935 case IrInstructionIdAtomicLoad:
2576124936 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);
25762 case IrInstructionIdPromiseResultType:
25763 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
25764 case IrInstructionIdAwaitBookkeeping:
25765 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
2576624937 case IrInstructionIdSaveErrRetAddr:
2576724938 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
2576824939 case IrInstructionIdAddImplicitReturnType:
2576924940 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
25770 case IrInstructionIdMergeErrRetTraces:
25771 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
25772 case IrInstructionIdMarkErrRetTracePtr:
25773 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
2577424941 case IrInstructionIdFloatOp:
2577524942 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
2577624943 case IrInstructionIdMulAdd:
......@@ -25797,6 +24964,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2579724964 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);
2579824965 case IrInstructionIdUnionInitNamedField:
2579924966 return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction);
24967 case IrInstructionIdSuspendBegin:
24968 return ir_analyze_instruction_suspend_begin(ira, (IrInstructionSuspendBegin *)instruction);
24969 case IrInstructionIdSuspendFinish:
24970 return ir_analyze_instruction_suspend_finish(ira, (IrInstructionSuspendFinish *)instruction);
24971 case IrInstructionIdResume:
24972 return ir_analyze_instruction_resume(ira, (IrInstructionResume *)instruction);
24973 case IrInstructionIdAwaitSrc:
24974 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
24975 case IrInstructionIdSpillBegin:
24976 return ir_analyze_instruction_spill_begin(ira, (IrInstructionSpillBegin *)instruction);
24977 case IrInstructionIdSpillEnd:
24978 return ir_analyze_instruction_spill_end(ira, (IrInstructionSpillEnd *)instruction);
2580024979 }
2580124980 zig_unreachable();
2580224981}
......@@ -25813,9 +24992,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
2581324992 old_exec->analysis = ira;
2581424993 ira->codegen = codegen;
2581524994
25816 ZigFn *fn_entry = exec_fn_entry(old_exec);
25817 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
25818 ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type;
24995 ira->explicit_return_type = expected_type;
2581924996 ira->explicit_return_type_source_node = expected_type_source_node;
2582024997
2582124998 ira->old_irb.codegen = codegen;
......@@ -25913,19 +25090,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2591325090 case IrInstructionIdPtrType:
2591425091 case IrInstructionIdSetAlignStack:
2591525092 case IrInstructionIdExport:
25916 case IrInstructionIdCancel:
25917 case IrInstructionIdCoroId:
25918 case IrInstructionIdCoroBegin:
25919 case IrInstructionIdCoroAllocFail:
25920 case IrInstructionIdCoroEnd:
25921 case IrInstructionIdCoroResume:
25922 case IrInstructionIdCoroSave:
25923 case IrInstructionIdCoroAllocHelper:
25924 case IrInstructionIdAwaitBookkeeping:
2592525093 case IrInstructionIdSaveErrRetAddr:
2592625094 case IrInstructionIdAddImplicitReturnType:
25927 case IrInstructionIdMergeErrRetTraces:
25928 case IrInstructionIdMarkErrRetTracePtr:
2592925095 case IrInstructionIdAtomicRmw:
2593025096 case IrInstructionIdCmpxchgGen:
2593125097 case IrInstructionIdCmpxchgSrc:
......@@ -25940,6 +25106,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2594025106 case IrInstructionIdOptionalWrap:
2594125107 case IrInstructionIdVectorToArray:
2594225108 case IrInstructionIdResetResult:
25109 case IrInstructionIdSuspendBegin:
25110 case IrInstructionIdSuspendFinish:
25111 case IrInstructionIdResume:
25112 case IrInstructionIdAwaitSrc:
25113 case IrInstructionIdAwaitGen:
25114 case IrInstructionIdSpillBegin:
2594325115 return true;
2594425116
2594525117 case IrInstructionIdPhi:
......@@ -25958,8 +25130,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2595825130 case IrInstructionIdTypeOf:
2595925131 case IrInstructionIdStructFieldPtr:
2596025132 case IrInstructionIdArrayType:
25961 case IrInstructionIdPromiseType:
2596225133 case IrInstructionIdSliceType:
25134 case IrInstructionIdAnyFrameType:
2596325135 case IrInstructionIdSizeOf:
2596425136 case IrInstructionIdTestNonNull:
2596525137 case IrInstructionIdOptionalUnwrapPtr:
......@@ -25985,7 +25157,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2598525157 case IrInstructionIdAlignOf:
2598625158 case IrInstructionIdReturnAddress:
2598725159 case IrInstructionIdFrameAddress:
25988 case IrInstructionIdHandle:
25160 case IrInstructionIdFrameHandle:
25161 case IrInstructionIdFrameType:
25162 case IrInstructionIdFrameSizeSrc:
25163 case IrInstructionIdFrameSizeGen:
2598925164 case IrInstructionIdTestErrSrc:
2599025165 case IrInstructionIdTestErrGen:
2599125166 case IrInstructionIdFnProto:
......@@ -26018,13 +25193,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2601825193 case IrInstructionIdTagType:
2601925194 case IrInstructionIdErrorReturnTrace:
2602025195 case IrInstructionIdErrorUnion:
26021 case IrInstructionIdGetImplicitAllocator:
26022 case IrInstructionIdCoroAlloc:
26023 case IrInstructionIdCoroSize:
26024 case IrInstructionIdCoroSuspend:
26025 case IrInstructionIdCoroFree:
26026 case IrInstructionIdCoroPromise:
26027 case IrInstructionIdPromiseResultType:
2602825196 case IrInstructionIdFloatOp:
2602925197 case IrInstructionIdMulAdd:
2603025198 case IrInstructionIdAtomicLoad:
......@@ -26041,7 +25209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2604125209 case IrInstructionIdHasDecl:
2604225210 case IrInstructionIdAllocaSrc:
2604325211 case IrInstructionIdAllocaGen:
26044 case IrInstructionIdResultPtr:
25212 case IrInstructionIdSpillEnd:
2604525213 return false;
2604625214
2604725215 case IrInstructionIdAsm:
src/ir.hpp+2
......@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
2828 AstNode *source_node);
2929const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
3030
31void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text);
32
3133#endif
src/ir_print.cpp+109-224
......@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
6464 }
6565}
6666
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *instruction) {
6868 fprintf(irp->f, "return ");
69 if (return_instruction->value != nullptr) {
70 ir_print_other_instruction(irp, return_instruction->value);
71 }
69 ir_print_other_instruction(irp, instruction->operand);
7270}
7371
7472static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
......@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
257255
258256static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {
259257 if (call_instruction->is_async) {
260 fprintf(irp->f, "async");
261 if (call_instruction->async_allocator != nullptr) {
262 fprintf(irp->f, "<");
263 ir_print_other_instruction(irp, call_instruction->async_allocator);
264 fprintf(irp->f, ">");
265 }
266 fprintf(irp->f, " ");
258 fprintf(irp->f, "async ");
267259 }
268260 if (call_instruction->fn_entry) {
269261 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
......@@ -284,13 +276,7 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi
284276
285277static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {
286278 if (call_instruction->is_async) {
287 fprintf(irp->f, "async");
288 if (call_instruction->async_allocator != nullptr) {
289 fprintf(irp->f, "<");
290 ir_print_other_instruction(irp, call_instruction->async_allocator);
291 fprintf(irp->f, ">");
292 }
293 fprintf(irp->f, " ");
279 fprintf(irp->f, "async ");
294280 }
295281 if (call_instruction->fn_entry) {
296282 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
......@@ -477,20 +463,21 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
477463 ir_print_other_instruction(irp, instruction->child_type);
478464}
479465
480static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) {
481 fprintf(irp->f, "promise");
482 if (instruction->payload_type != nullptr) {
483 fprintf(irp->f, "->");
484 ir_print_other_instruction(irp, instruction->payload_type);
485 }
486}
487
488466static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
489467 const char *const_kw = instruction->is_const ? "const " : "";
490468 fprintf(irp->f, "[]%s", const_kw);
491469 ir_print_other_instruction(irp, instruction->child_type);
492470}
493471
472static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *instruction) {
473 if (instruction->payload_type == nullptr) {
474 fprintf(irp->f, "anyframe");
475 } else {
476 fprintf(irp->f, "anyframe->");
477 ir_print_other_instruction(irp, instruction->payload_type);
478 }
479}
480
494481static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {
495482 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));
496483}
......@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
926913 fprintf(irp->f, "@frameAddress()");
927914}
928915
929static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {
930 fprintf(irp->f, "@handle()");
916static void ir_print_handle(IrPrint *irp, IrInstructionFrameHandle *instruction) {
917 fprintf(irp->f, "@frame()");
918}
919
920static void ir_print_frame_type(IrPrint *irp, IrInstructionFrameType *instruction) {
921 fprintf(irp->f, "@Frame(");
922 ir_print_other_instruction(irp, instruction->fn);
923 fprintf(irp->f, ")");
924}
925
926static void ir_print_frame_size_src(IrPrint *irp, IrInstructionFrameSizeSrc *instruction) {
927 fprintf(irp->f, "@frameSize(");
928 ir_print_other_instruction(irp, instruction->fn);
929 fprintf(irp->f, ")");
930}
931
932static void ir_print_frame_size_gen(IrPrint *irp, IrInstructionFrameSizeGen *instruction) {
933 fprintf(irp->f, "@frameSize(");
934 ir_print_other_instruction(irp, instruction->fn);
935 fprintf(irp->f, ")");
931936}
932937
933938static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
......@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru
13221327 fprintf(irp->f, ")");
13231328}
13241329
1325static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) {
1326 fprintf(irp->f, "ResultPtr(");
1327 ir_print_result_loc(irp, instruction->result_loc);
1328 fprintf(irp->f, ",");
1329 ir_print_other_instruction(irp, instruction->result);
1330 fprintf(irp->f, ")");
1331}
1332
13331330static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
13341331 fprintf(irp->f, "@OpaqueType()");
13351332}
......@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
13911388 ir_print_other_instruction(irp, instruction->payload);
13921389}
13931390
1394static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
1395 fprintf(irp->f, "cancel ");
1396 ir_print_other_instruction(irp, instruction->target);
1397}
1398
1399static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplicitAllocator *instruction) {
1400 fprintf(irp->f, "@getImplicitAllocator(");
1401 switch (instruction->id) {
1402 case ImplicitAllocatorIdArg:
1403 fprintf(irp->f, "Arg");
1404 break;
1405 case ImplicitAllocatorIdLocalVar:
1406 fprintf(irp->f, "LocalVar");
1407 break;
1408 }
1409 fprintf(irp->f, ")");
1410}
1411
1412static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1413 fprintf(irp->f, "@coroId(");
1414 ir_print_other_instruction(irp, instruction->promise_ptr);
1415 fprintf(irp->f, ")");
1416}
1417
1418static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
1419 fprintf(irp->f, "@coroAlloc(");
1420 ir_print_other_instruction(irp, instruction->coro_id);
1421 fprintf(irp->f, ")");
1422}
1423
1424static void ir_print_coro_size(IrPrint *irp, IrInstructionCoroSize *instruction) {
1425 fprintf(irp->f, "@coroSize()");
1426}
1427
1428static void ir_print_coro_begin(IrPrint *irp, IrInstructionCoroBegin *instruction) {
1429 fprintf(irp->f, "@coroBegin(");
1430 ir_print_other_instruction(irp, instruction->coro_id);
1431 fprintf(irp->f, ",");
1432 ir_print_other_instruction(irp, instruction->coro_mem_ptr);
1433 fprintf(irp->f, ")");
1434}
1435
1436static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *instruction) {
1437 fprintf(irp->f, "@coroAllocFail(");
1438 ir_print_other_instruction(irp, instruction->err_val);
1439 fprintf(irp->f, ")");
1440}
1441
1442static void ir_print_coro_suspend(IrPrint *irp, IrInstructionCoroSuspend *instruction) {
1443 fprintf(irp->f, "@coroSuspend(");
1444 if (instruction->save_point != nullptr) {
1445 ir_print_other_instruction(irp, instruction->save_point);
1446 } else {
1447 fprintf(irp->f, "null");
1448 }
1449 fprintf(irp->f, ",");
1450 ir_print_other_instruction(irp, instruction->is_final);
1451 fprintf(irp->f, ")");
1452}
1453
1454static void ir_print_coro_end(IrPrint *irp, IrInstructionCoroEnd *instruction) {
1455 fprintf(irp->f, "@coroEnd()");
1456}
1457
1458static void ir_print_coro_free(IrPrint *irp, IrInstructionCoroFree *instruction) {
1459 fprintf(irp->f, "@coroFree(");
1460 ir_print_other_instruction(irp, instruction->coro_id);
1461 fprintf(irp->f, ",");
1462 ir_print_other_instruction(irp, instruction->coro_handle);
1463 fprintf(irp->f, ")");
1464}
1465
1466static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) {
1467 fprintf(irp->f, "@coroResume(");
1468 ir_print_other_instruction(irp, instruction->awaiter_handle);
1469 fprintf(irp->f, ")");
1470}
1471
1472static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction) {
1473 fprintf(irp->f, "@coroSave(");
1474 ir_print_other_instruction(irp, instruction->coro_handle);
1475 fprintf(irp->f, ")");
1476}
1477
1478static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1479 fprintf(irp->f, "@coroPromise(");
1480 ir_print_other_instruction(irp, instruction->coro_handle);
1481 fprintf(irp->f, ")");
1482}
1483
1484static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1485 fprintf(irp->f, "@PromiseResultType(");
1486 ir_print_other_instruction(irp, instruction->promise_type);
1487 fprintf(irp->f, ")");
1488}
1489
1490static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
1491 fprintf(irp->f, "@coroAllocHelper(");
1492 ir_print_other_instruction(irp, instruction->realloc_fn);
1493 fprintf(irp->f, ",");
1494 ir_print_other_instruction(irp, instruction->coro_size);
1495 fprintf(irp->f, ")");
1496}
1497
14981391static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
14991392 fprintf(irp->f, "@atomicRmw(");
15001393 if (instruction->operand_type != nullptr) {
......@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct
15391432 fprintf(irp->f, ")");
15401433}
15411434
1542static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
1543 fprintf(irp->f, "@awaitBookkeeping(");
1544 ir_print_other_instruction(irp, instruction->promise_result_type);
1545 fprintf(irp->f, ")");
1546}
1547
15481435static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
15491436 fprintf(irp->f, "@saveErrRetAddr()");
15501437}
......@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
15551442 fprintf(irp->f, ")");
15561443}
15571444
1558static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1559 fprintf(irp->f, "@mergeErrRetTraces(");
1560 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1561 fprintf(irp->f, ",");
1562 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1563 fprintf(irp->f, ",");
1564 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1565 fprintf(irp->f, ")");
1566}
1567
1568static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1569 fprintf(irp->f, "@markErrRetTracePtr(");
1570 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1571 fprintf(irp->f, ")");
1572}
1573
15741445static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
15751446
15761447 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
......@@ -1638,6 +1509,47 @@ static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInit
16381509 fprintf(irp->f, ")");
16391510}
16401511
1512static void ir_print_suspend_begin(IrPrint *irp, IrInstructionSuspendBegin *instruction) {
1513 fprintf(irp->f, "@suspendBegin()");
1514}
1515
1516static void ir_print_suspend_finish(IrPrint *irp, IrInstructionSuspendFinish *instruction) {
1517 fprintf(irp->f, "@suspendFinish()");
1518}
1519
1520static void ir_print_resume(IrPrint *irp, IrInstructionResume *instruction) {
1521 fprintf(irp->f, "resume ");
1522 ir_print_other_instruction(irp, instruction->frame);
1523}
1524
1525static void ir_print_await_src(IrPrint *irp, IrInstructionAwaitSrc *instruction) {
1526 fprintf(irp->f, "@await(");
1527 ir_print_other_instruction(irp, instruction->frame);
1528 fprintf(irp->f, ",");
1529 ir_print_result_loc(irp, instruction->result_loc);
1530 fprintf(irp->f, ")");
1531}
1532
1533static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction) {
1534 fprintf(irp->f, "@await(");
1535 ir_print_other_instruction(irp, instruction->frame);
1536 fprintf(irp->f, ",");
1537 ir_print_other_instruction(irp, instruction->result_loc);
1538 fprintf(irp->f, ")");
1539}
1540
1541static void ir_print_spill_begin(IrPrint *irp, IrInstructionSpillBegin *instruction) {
1542 fprintf(irp->f, "@spillBegin(");
1543 ir_print_other_instruction(irp, instruction->operand);
1544 fprintf(irp->f, ")");
1545}
1546
1547static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) {
1548 fprintf(irp->f, "@spillEnd(");
1549 ir_print_other_instruction(irp, &instruction->begin->base);
1550 fprintf(irp->f, ")");
1551}
1552
16411553static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16421554 ir_print_prefix(irp, instruction);
16431555 switch (instruction->id) {
......@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
17271639 case IrInstructionIdArrayType:
17281640 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
17291641 break;
1730 case IrInstructionIdPromiseType:
1731 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1732 break;
17331642 case IrInstructionIdSliceType:
17341643 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
17351644 break;
1645 case IrInstructionIdAnyFrameType:
1646 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
1647 break;
17361648 case IrInstructionIdGlobalAsm:
17371649 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);
17381650 break;
......@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
18861798 case IrInstructionIdFrameAddress:
18871799 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
18881800 break;
1889 case IrInstructionIdHandle:
1890 ir_print_handle(irp, (IrInstructionHandle *)instruction);
1801 case IrInstructionIdFrameHandle:
1802 ir_print_handle(irp, (IrInstructionFrameHandle *)instruction);
1803 break;
1804 case IrInstructionIdFrameType:
1805 ir_print_frame_type(irp, (IrInstructionFrameType *)instruction);
1806 break;
1807 case IrInstructionIdFrameSizeSrc:
1808 ir_print_frame_size_src(irp, (IrInstructionFrameSizeSrc *)instruction);
1809 break;
1810 case IrInstructionIdFrameSizeGen:
1811 ir_print_frame_size_gen(irp, (IrInstructionFrameSizeGen *)instruction);
18911812 break;
18921813 case IrInstructionIdAlignOf:
18931814 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
......@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20061927 case IrInstructionIdResetResult:
20071928 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);
20081929 break;
2009 case IrInstructionIdResultPtr:
2010 ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
2011 break;
20121930 case IrInstructionIdOpaqueType:
20131931 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
20141932 break;
......@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20301948 case IrInstructionIdErrorUnion:
20311949 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
20321950 break;
2033 case IrInstructionIdCancel:
2034 ir_print_cancel(irp, (IrInstructionCancel *)instruction);
2035 break;
2036 case IrInstructionIdGetImplicitAllocator:
2037 ir_print_get_implicit_allocator(irp, (IrInstructionGetImplicitAllocator *)instruction);
2038 break;
2039 case IrInstructionIdCoroId:
2040 ir_print_coro_id(irp, (IrInstructionCoroId *)instruction);
2041 break;
2042 case IrInstructionIdCoroAlloc:
2043 ir_print_coro_alloc(irp, (IrInstructionCoroAlloc *)instruction);
2044 break;
2045 case IrInstructionIdCoroSize:
2046 ir_print_coro_size(irp, (IrInstructionCoroSize *)instruction);
2047 break;
2048 case IrInstructionIdCoroBegin:
2049 ir_print_coro_begin(irp, (IrInstructionCoroBegin *)instruction);
2050 break;
2051 case IrInstructionIdCoroAllocFail:
2052 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);
2053 break;
2054 case IrInstructionIdCoroSuspend:
2055 ir_print_coro_suspend(irp, (IrInstructionCoroSuspend *)instruction);
2056 break;
2057 case IrInstructionIdCoroEnd:
2058 ir_print_coro_end(irp, (IrInstructionCoroEnd *)instruction);
2059 break;
2060 case IrInstructionIdCoroFree:
2061 ir_print_coro_free(irp, (IrInstructionCoroFree *)instruction);
2062 break;
2063 case IrInstructionIdCoroResume:
2064 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
2065 break;
2066 case IrInstructionIdCoroSave:
2067 ir_print_coro_save(irp, (IrInstructionCoroSave *)instruction);
2068 break;
2069 case IrInstructionIdCoroAllocHelper:
2070 ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction);
2071 break;
20721951 case IrInstructionIdAtomicRmw:
20731952 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
20741953 break;
2075 case IrInstructionIdCoroPromise:
2076 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
2077 break;
2078 case IrInstructionIdPromiseResultType:
2079 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
2080 break;
2081 case IrInstructionIdAwaitBookkeeping:
2082 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
2083 break;
20841954 case IrInstructionIdSaveErrRetAddr:
20851955 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
20861956 break;
20871957 case IrInstructionIdAddImplicitReturnType:
20881958 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
20891959 break;
2090 case IrInstructionIdMergeErrRetTraces:
2091 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
2092 break;
2093 case IrInstructionIdMarkErrRetTracePtr:
2094 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
2095 break;
20961960 case IrInstructionIdFloatOp:
20971961 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
20981962 break;
......@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
21472011 case IrInstructionIdUnionInitNamedField:
21482012 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);
21492013 break;
2014 case IrInstructionIdSuspendBegin:
2015 ir_print_suspend_begin(irp, (IrInstructionSuspendBegin *)instruction);
2016 break;
2017 case IrInstructionIdSuspendFinish:
2018 ir_print_suspend_finish(irp, (IrInstructionSuspendFinish *)instruction);
2019 break;
2020 case IrInstructionIdResume:
2021 ir_print_resume(irp, (IrInstructionResume *)instruction);
2022 break;
2023 case IrInstructionIdAwaitSrc:
2024 ir_print_await_src(irp, (IrInstructionAwaitSrc *)instruction);
2025 break;
2026 case IrInstructionIdAwaitGen:
2027 ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction);
2028 break;
2029 case IrInstructionIdSpillBegin:
2030 ir_print_spill_begin(irp, (IrInstructionSpillBegin *)instruction);
2031 break;
2032 case IrInstructionIdSpillEnd:
2033 ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction);
2034 break;
21502035 }
21512036 fprintf(irp->f, "\n");
21522037}
src/main.cpp+1-1
......@@ -85,7 +85,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
8585 " --verbose-cc enable compiler debug output for C compilation\n"
8686 " -dirafter [dir] same as -isystem but do it last\n"
8787 " -isystem [dir] add additional search path for other .h files\n"
88 " -mllvm [arg] forward an arg to LLVM's option processing\n"
88 " -mllvm [arg] (unsupported) forward an arg to LLVM's option processing\n"
8989 " --override-std-dir [arg] override path to Zig standard library\n"
9090 " --override-lib-dir [arg] override path to Zig lib library\n"
9191 " -ffunction-sections places each function in a seperate section\n"
src/parser.cpp+26-64
......@@ -113,7 +113,6 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc);
113113static AstNode *ast_parse_prefix_op(ParseContext *pc);
114114static AstNode *ast_parse_prefix_type_op(ParseContext *pc);
115115static AstNode *ast_parse_suffix_op(ParseContext *pc);
116static AstNode *ast_parse_async_prefix(ParseContext *pc);
117116static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc);
118117static AstNode *ast_parse_array_type_start(ParseContext *pc);
119118static AstNode *ast_parse_ptr_type_start(ParseContext *pc);
......@@ -282,8 +281,8 @@ static AstNode *ast_parse_prefix_op_expr(
282281 case NodeTypeAwaitExpr:
283282 right = &prefix->data.await_expr.expr;
284283 break;
285 case NodeTypePromiseType:
286 right = &prefix->data.promise_type.payload_type;
284 case NodeTypeAnyFrameType:
285 right = &prefix->data.anyframe_type.payload_type;
287286 break;
288287 case NodeTypeArrayType:
289288 right = &prefix->data.array_type.child_type;
......@@ -1167,7 +1166,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
11671166// <- AsmExpr
11681167// / IfExpr
11691168// / KEYWORD_break BreakLabel? Expr?
1170// / KEYWORD_cancel Expr
11711169// / KEYWORD_comptime Expr
11721170// / KEYWORD_continue BreakLabel?
11731171// / KEYWORD_resume Expr
......@@ -1195,14 +1193,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
11951193 return res;
11961194 }
11971195
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
12061196 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);
12071197 if (comptime != nullptr) {
12081198 AstNode *expr = ast_expect(pc, ast_parse_expr);
......@@ -1398,22 +1388,18 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
13981388}
13991389
14001390// SuffixExpr
1401// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
1391// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
14021392// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
14031393static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
1404 AstNode *async_call = ast_parse_async_prefix(pc);
1405 if (async_call != nullptr) {
1394 Token *async_token = eat_token_if(pc, TokenIdKeywordAsync);
1395 if (async_token != nullptr) {
14061396 if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
14071397 // HACK: If we see the keyword `fn`, then we assume that
14081398 // we are parsing an async fn proto, and not a call.
14091399 // We therefore put back all tokens consumed by the async
14101400 // prefix...
1411 // HACK: This loop is not actually enough to put back all the
1412 // tokens. Let's hope this is fine for most code right now
1413 // and wait till we get the async rework for a syntax update.
1414 do {
1415 put_back_token(pc);
1416 } while (peek_token(pc)->id != TokenIdKeywordAsync);
1401 put_back_token(pc);
1402 put_back_token(pc);
14171403
14181404 return ast_parse_primary_type_expr(pc);
14191405 }
......@@ -1455,10 +1441,14 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
14551441 ast_invalid_token_error(pc, peek_token(pc));
14561442
14571443 assert(args->type == NodeTypeFnCallExpr);
1458 async_call->data.fn_call_expr.fn_ref_expr = child;
1459 async_call->data.fn_call_expr.params = args->data.fn_call_expr.params;
1460 async_call->data.fn_call_expr.is_builtin = false;
1461 return async_call;
1444
1445 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token);
1446 res->data.fn_call_expr.is_async = true;
1447 res->data.fn_call_expr.seen = false;
1448 res->data.fn_call_expr.fn_ref_expr = child;
1449 res->data.fn_call_expr.params = args->data.fn_call_expr.params;
1450 res->data.fn_call_expr.is_builtin = false;
1451 return res;
14621452 }
14631453
14641454 AstNode *res = ast_parse_primary_type_expr(pc);
......@@ -1510,7 +1500,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
15101500// <- BUILTINIDENTIFIER FnCallArguments
15111501// / CHAR_LITERAL
15121502// / ContainerDecl
1513// / DOT IDENTIFIER
1503// / DOT IDENTIFIER
15141504// / ErrorSetDecl
15151505// / FLOAT
15161506// / FnProto
......@@ -1643,9 +1633,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
16431633 if (null != nullptr)
16441634 return ast_create_node(pc, NodeTypeNullLiteral, null);
16451635
1646 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);
1647 if (promise != nullptr)
1648 return ast_create_node(pc, NodeTypePromiseType, promise);
1636 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
1637 if (anyframe != nullptr)
1638 return ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
16491639
16501640 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);
16511641 if (true_token != nullptr) {
......@@ -2025,7 +2015,7 @@ static AstNode *ast_parse_link_section(ParseContext *pc) {
20252015// <- KEYWORD_nakedcc
20262016// / KEYWORD_stdcallcc
20272017// / KEYWORD_extern
2028// / KEYWORD_async (LARROW TypeExpr RARROW)?
2018// / KEYWORD_async
20292019static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
20302020 AstNodeFnProto res = {};
20312021 if (eat_token_if(pc, TokenIdKeywordNakedCC) != nullptr) {
......@@ -2042,11 +2032,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
20422032 }
20432033 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {
20442034 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);
20502035 return Optional<AstNodeFnProto>::some(res);
20512036 }
20522037
......@@ -2522,7 +2507,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
25222507
25232508// PrefixTypeOp
25242509// <- QUESTIONMARK
2525// / KEYWORD_promise MINUSRARROW
2510// / KEYWORD_anyframe MINUSRARROW
25262511// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
25272512// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
25282513static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
......@@ -2533,10 +2518,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
25332518 return res;
25342519 }
25352520
2536 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);
2537 if (promise != nullptr) {
2521 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
2522 if (anyframe != nullptr) {
25382523 if (eat_token_if(pc, TokenIdArrow) != nullptr) {
2539 AstNode *res = ast_create_node(pc, NodeTypePromiseType, promise);
2524 AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
25402525 return res;
25412526 }
25422527
......@@ -2671,24 +2656,6 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) {
26712656 return nullptr;
26722657}
26732658
2674// AsyncPrefix <- KEYWORD_async (LARROW PrefixExpr RARROW)?
2675static AstNode *ast_parse_async_prefix(ParseContext *pc) {
2676 Token *async = eat_token_if(pc, TokenIdKeywordAsync);
2677 if (async == nullptr)
2678 return nullptr;
2679
2680 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
2681 res->data.fn_call_expr.is_async = true;
2682 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 }
2688
2689 return res;
2690}
2691
26922659// FnCallArguments <- LPAREN ExprList RPAREN
26932660static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {
26942661 Token *paren = eat_token_if(pc, TokenIdLParen);
......@@ -2858,7 +2825,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
28582825 visit_node_list(&node->data.fn_proto.params, visit, context);
28592826 visit_field(&node->data.fn_proto.align_expr, visit, context);
28602827 visit_field(&node->data.fn_proto.section_expr, visit, context);
2861 visit_field(&node->data.fn_proto.async_allocator_type, visit, context);
28622828 break;
28632829 case NodeTypeFnDef:
28642830 visit_field(&node->data.fn_def.fn_proto, visit, context);
......@@ -2918,7 +2884,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29182884 case NodeTypeFnCallExpr:
29192885 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
29202886 visit_node_list(&node->data.fn_call_expr.params, visit, context);
2921 visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
29222887 break;
29232888 case NodeTypeArrayAccessExpr:
29242889 visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);
......@@ -3034,8 +2999,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30342999 case NodeTypeInferredArrayType:
30353000 visit_field(&node->data.array_type.child_type, visit, context);
30363001 break;
3037 case NodeTypePromiseType:
3038 visit_field(&node->data.promise_type.payload_type, visit, context);
3002 case NodeTypeAnyFrameType:
3003 visit_field(&node->data.anyframe_type.payload_type, visit, context);
30393004 break;
30403005 case NodeTypeErrorType:
30413006 // none
......@@ -3047,9 +3012,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
30473012 case NodeTypeErrorSetDecl:
30483013 visit_node_list(&node->data.err_set_decl.decls, visit, context);
30493014 break;
3050 case NodeTypeCancel:
3051 visit_field(&node->data.cancel_expr.expr, visit, context);
3052 break;
30533015 case NodeTypeResume:
30543016 visit_field(&node->data.resume_expr.expr, visit, context);
30553017 break;
src/target.cpp+61-1
......@@ -665,7 +665,63 @@ ZigLLVM_SubArchType target_subarch_enum(SubArchList sub_arch_list, size_t i) {
665665}
666666
667667const char *target_subarch_name(ZigLLVM_SubArchType subarch) {
668 return ZigLLVMGetSubArchTypeName(subarch);
668 switch (subarch) {
669 case ZigLLVM_NoSubArch:
670 return "";
671 case ZigLLVM_ARMSubArch_v8_5a:
672 return "v8_5a";
673 case ZigLLVM_ARMSubArch_v8_4a:
674 return "v8_4a";
675 case ZigLLVM_ARMSubArch_v8_3a:
676 return "v8_3a";
677 case ZigLLVM_ARMSubArch_v8_2a:
678 return "v8_2a";
679 case ZigLLVM_ARMSubArch_v8_1a:
680 return "v8_1a";
681 case ZigLLVM_ARMSubArch_v8:
682 return "v8";
683 case ZigLLVM_ARMSubArch_v8r:
684 return "v8r";
685 case ZigLLVM_ARMSubArch_v8m_baseline:
686 return "v8m_baseline";
687 case ZigLLVM_ARMSubArch_v8m_mainline:
688 return "v8m_mainline";
689 case ZigLLVM_ARMSubArch_v7:
690 return "v7";
691 case ZigLLVM_ARMSubArch_v7em:
692 return "v7em";
693 case ZigLLVM_ARMSubArch_v7m:
694 return "v7m";
695 case ZigLLVM_ARMSubArch_v7s:
696 return "v7s";
697 case ZigLLVM_ARMSubArch_v7k:
698 return "v7k";
699 case ZigLLVM_ARMSubArch_v7ve:
700 return "v7ve";
701 case ZigLLVM_ARMSubArch_v6:
702 return "v6";
703 case ZigLLVM_ARMSubArch_v6m:
704 return "v6m";
705 case ZigLLVM_ARMSubArch_v6k:
706 return "v6k";
707 case ZigLLVM_ARMSubArch_v6t2:
708 return "v6t2";
709 case ZigLLVM_ARMSubArch_v5:
710 return "v5";
711 case ZigLLVM_ARMSubArch_v5te:
712 return "v5te";
713 case ZigLLVM_ARMSubArch_v4t:
714 return "v4t";
715 case ZigLLVM_KalimbaSubArch_v3:
716 return "v3";
717 case ZigLLVM_KalimbaSubArch_v4:
718 return "v4";
719 case ZigLLVM_KalimbaSubArch_v5:
720 return "v5";
721 case ZigLLVM_MipsSubArch_r6:
722 return "r6";
723 }
724 zig_unreachable();
669725}
670726
671727size_t target_subarch_list_count(void) {
......@@ -1827,3 +1883,7 @@ bool target_libc_needs_crti_crtn(const ZigTarget *target) {
18271883bool target_is_riscv(const ZigTarget *target) {
18281884 return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64;
18291885}
1886
1887unsigned target_fn_align(const ZigTarget *target) {
1888 return 16;
1889}
src/target.hpp+2
......@@ -201,4 +201,6 @@ size_t target_libc_count(void);
201201void target_libc_enum(size_t index, ZigTarget *out_target);
202202bool target_libc_needs_crti_crtn(const ZigTarget *target);
203203
204unsigned target_fn_align(const ZigTarget *target);
205
204206#endif
src/tokenizer.cpp+2-4
......@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {
109109 {"align", TokenIdKeywordAlign},
110110 {"allowzero", TokenIdKeywordAllowZero},
111111 {"and", TokenIdKeywordAnd},
112 {"anyframe", TokenIdKeywordAnyFrame},
112113 {"asm", TokenIdKeywordAsm},
113114 {"async", TokenIdKeywordAsync},
114115 {"await", TokenIdKeywordAwait},
115116 {"break", TokenIdKeywordBreak},
116 {"cancel", TokenIdKeywordCancel},
117117 {"catch", TokenIdKeywordCatch},
118118 {"comptime", TokenIdKeywordCompTime},
119119 {"const", TokenIdKeywordConst},
......@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {
136136 {"or", TokenIdKeywordOr},
137137 {"orelse", TokenIdKeywordOrElse},
138138 {"packed", TokenIdKeywordPacked},
139 {"promise", TokenIdKeywordPromise},
140139 {"pub", TokenIdKeywordPub},
141140 {"resume", TokenIdKeywordResume},
142141 {"return", TokenIdKeywordReturn},
......@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {
15311530 case TokenIdKeywordAwait: return "await";
15321531 case TokenIdKeywordResume: return "resume";
15331532 case TokenIdKeywordSuspend: return "suspend";
1534 case TokenIdKeywordCancel: return "cancel";
15351533 case TokenIdKeywordAlign: return "align";
15361534 case TokenIdKeywordAnd: return "and";
1535 case TokenIdKeywordAnyFrame: return "anyframe";
15371536 case TokenIdKeywordAsm: return "asm";
15381537 case TokenIdKeywordBreak: return "break";
15391538 case TokenIdKeywordCatch: return "catch";
......@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {
15581557 case TokenIdKeywordOr: return "or";
15591558 case TokenIdKeywordOrElse: return "orelse";
15601559 case TokenIdKeywordPacked: return "packed";
1561 case TokenIdKeywordPromise: return "promise";
15621560 case TokenIdKeywordPub: return "pub";
15631561 case TokenIdKeywordReturn: return "return";
15641562 case TokenIdKeywordLinkSection: return "linksection";
src/tokenizer.hpp+1-2
......@@ -53,11 +53,11 @@ enum TokenId {
5353 TokenIdKeywordAlign,
5454 TokenIdKeywordAllowZero,
5555 TokenIdKeywordAnd,
56 TokenIdKeywordAnyFrame,
5657 TokenIdKeywordAsm,
5758 TokenIdKeywordAsync,
5859 TokenIdKeywordAwait,
5960 TokenIdKeywordBreak,
60 TokenIdKeywordCancel,
6161 TokenIdKeywordCatch,
6262 TokenIdKeywordCompTime,
6363 TokenIdKeywordConst,
......@@ -81,7 +81,6 @@ enum TokenId {
8181 TokenIdKeywordOr,
8282 TokenIdKeywordOrElse,
8383 TokenIdKeywordPacked,
84 TokenIdKeywordPromise,
8584 TokenIdKeywordPub,
8685 TokenIdKeywordResume,
8786 TokenIdKeywordReturn,
src/zig_llvm.cpp+16-11
......@@ -42,7 +42,6 @@
4242#include <llvm/Support/TargetRegistry.h>
4343#include <llvm/Target/TargetMachine.h>
4444#include <llvm/Target/CodeGenCWrappers.h>
45#include <llvm/Transforms/Coroutines.h>
4645#include <llvm/Transforms/IPO.h>
4746#include <llvm/Transforms/IPO/AlwaysInliner.h>
4847#include <llvm/Transforms/IPO/PassManagerBuilder.h>
......@@ -202,8 +201,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
202201 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
203202 }
204203
205 addCoroutinePassesToExtensionPoints(*PMBuilder);
206
207204 // Set up the per-function pass manager.
208205 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
209206 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
......@@ -797,25 +794,25 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
797794 case ZigLLVM_NoSubArch:
798795 return "";
799796 case ZigLLVM_ARMSubArch_v8_5a:
800 return "v8_5a";
797 return "v8.5a";
801798 case ZigLLVM_ARMSubArch_v8_4a:
802 return "v8_4a";
799 return "v8.4a";
803800 case ZigLLVM_ARMSubArch_v8_3a:
804 return "v8_3a";
801 return "v8.3a";
805802 case ZigLLVM_ARMSubArch_v8_2a:
806 return "v8_2a";
803 return "v8.2a";
807804 case ZigLLVM_ARMSubArch_v8_1a:
808 return "v8_1a";
805 return "v8.1a";
809806 case ZigLLVM_ARMSubArch_v8:
810807 return "v8";
811808 case ZigLLVM_ARMSubArch_v8r:
812809 return "v8r";
813810 case ZigLLVM_ARMSubArch_v8m_baseline:
814 return "v8m_baseline";
811 return "v8m.base";
815812 case ZigLLVM_ARMSubArch_v8m_mainline:
816 return "v8m_mainline";
813 return "v8m.main";
817814 case ZigLLVM_ARMSubArch_v8_1m_mainline:
818 return "v8_1m_mainline";
815 return "v8.1m.main";
819816 case ZigLLVM_ARMSubArch_v7:
820817 return "v7";
821818 case ZigLLVM_ARMSubArch_v7em:
......@@ -909,6 +906,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
909906 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
910907}
911908
909void ZigLLVMSetTailCall(LLVMValueRef Call) {
910 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);
911}
912
913void ZigLLVMFunctionSetPrefixData(LLVMValueRef function, LLVMValueRef data) {
914 unwrap<Function>(function)->setPrefixData(unwrap<Constant>(data));
915}
916
912917
913918class MyOStream: public raw_ostream {
914919 public:
src/zig_llvm.h+2
......@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde
211211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
212212
213213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
214ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call);
215ZIG_EXTERN_C void ZigLLVMFunctionSetPrefixData(LLVMValueRef fn, LLVMValueRef data);
214216
215217ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
216218ZIG_EXTERN_C void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val);
std/c/freebsd.zig+1
......@@ -6,3 +6,4 @@ pub const _errno = __error;
66
77pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
88pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
9pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
std/debug.zig+1-2
......@@ -1024,8 +1024,7 @@ pub fn openElfDebugInfo(
10241024 elf_seekable_stream: *DwarfSeekableStream,
10251025 elf_in_stream: *DwarfInStream,
10261026) !DwarfInfo {
1027 var efile: elf.Elf = undefined;
1028 try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
1027 var efile = try elf.Elf.openStream(allocator, elf_seekable_stream, elf_in_stream);
10291028 errdefer efile.close();
10301029
10311030 var di = DwarfInfo{
std/elf.zig+6-9
......@@ -356,7 +356,6 @@ pub const SectionHeader = struct {
356356pub const Elf = struct {
357357 seekable_stream: *io.SeekableStream(anyerror, anyerror),
358358 in_stream: *io.InStream(anyerror),
359 auto_close_stream: bool,
360359 is_64: bool,
361360 endian: builtin.Endian,
362361 file_type: FileType,
......@@ -368,25 +367,23 @@ pub const Elf = struct {
368367 string_section: *SectionHeader,
369368 section_headers: []SectionHeader,
370369 allocator: *mem.Allocator,
371 prealloc_file: File,
372370
373371 /// Call close when done.
374 pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
372 pub fn openPath(allocator: *mem.Allocator, path: []const u8) !Elf {
375373 @compileError("TODO implement");
376374 }
377375
378376 /// Call close when done.
379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: File) !void {
377 pub fn openFile(allocator: *mem.Allocator, file: File) !Elf {
380378 @compileError("TODO implement");
381379 }
382380
383381 pub fn openStream(
384 elf: *Elf,
385382 allocator: *mem.Allocator,
386383 seekable_stream: *io.SeekableStream(anyerror, anyerror),
387384 in: *io.InStream(anyerror),
388 ) !void {
389 elf.auto_close_stream = false;
385 ) !Elf {
386 var elf: Elf = undefined;
390387 elf.allocator = allocator;
391388 elf.seekable_stream = seekable_stream;
392389 elf.in_stream = in;
......@@ -523,12 +520,12 @@ pub const Elf = struct {
523520 // not a string table
524521 return error.InvalidFormat;
525522 }
523
524 return elf;
526525 }
527526
528527 pub fn close(elf: *Elf) void {
529528 elf.allocator.free(elf.section_headers);
530
531 if (elf.auto_close_stream) elf.prealloc_file.close();
532529 }
533530
534531 pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
std/event/channel.zig+45-72
......@@ -2,8 +2,6 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const Loop = std.event.Loop;
86
97/// many producer, many consumer, thread-safe, runtime configurable buffer size
......@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {
7775 /// must be called when all calls to put and get have suspended and no more calls occur
7876 pub fn destroy(self: *SelfChannel) void {
7977 while (self.getters.get()) |get_node| {
80 cancel get_node.data.tick_node.data;
78 resume get_node.data.tick_node.data;
8179 }
8280 while (self.putters.get()) |put_node| {
83 cancel put_node.data.tick_node.data;
81 resume put_node.data.tick_node.data;
8482 }
8583 self.loop.allocator.free(self.buffer_nodes);
8684 self.loop.allocator.destroy(self);
8785 }
8886
89 /// puts a data item in the channel. The promise completes when the value has been added to the
87 /// puts a data item in the channel. The function returns when the value has been added to the
9088 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
91 pub async fn put(self: *SelfChannel, data: T) void {
92 // TODO fix this workaround
93 suspend {
94 resume @handle();
95 }
96
97 var my_tick_node = Loop.NextTickNode.init(@handle());
89 /// Or when the channel is destroyed.
90 pub fn put(self: *SelfChannel, data: T) void {
91 var my_tick_node = Loop.NextTickNode.init(@frame());
9892 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{
9993 .tick_node = &my_tick_node,
10094 .data = data,
......@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {
10296
10397 // TODO test canceling a put()
10498 errdefer {
105 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
99 _ = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
106100 const need_dispatch = !self.putters.remove(&queue_node);
107101 self.loop.cancelOnNextTick(&my_tick_node);
108102 if (need_dispatch) {
109103 // oops we made the put_count incorrect for a period of time. fix by dispatching.
110 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
104 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
111105 self.dispatch();
112106 }
113107 }
114108 suspend {
115109 self.putters.put(&queue_node);
116 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
110 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
117111
118112 self.dispatch();
119113 }
120114 }
121115
122 /// await this function to get an item from the channel. If the buffer is empty, the promise will
116 /// await this function to get an item from the channel. If the buffer is empty, the frame will
123117 /// complete when the next item is put in the channel.
124118 pub async fn get(self: *SelfChannel) T {
125 // TODO fix this workaround
126 suspend {
127 resume @handle();
128 }
129
130 // TODO integrate this function with named return values
131 // so we can get rid of this extra result copy
119 // TODO https://github.com/ziglang/zig/issues/2765
132120 var result: T = undefined;
133 var my_tick_node = Loop.NextTickNode.init(@handle());
121 var my_tick_node = Loop.NextTickNode.init(@frame());
134122 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
135123 .tick_node = &my_tick_node,
136124 .data = GetNode.Data{
......@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {
140128
141129 // TODO test canceling a get()
142130 errdefer {
143 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
131 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
144132 const need_dispatch = !self.getters.remove(&queue_node);
145133 self.loop.cancelOnNextTick(&my_tick_node);
146134 if (need_dispatch) {
147135 // oops we made the get_count incorrect for a period of time. fix by dispatching.
148 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
136 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
149137 self.dispatch();
150138 }
151139 }
152140
153141 suspend {
154142 self.getters.put(&queue_node);
155 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
143 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
156144
157145 self.dispatch();
158146 }
......@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {
173161 /// Await is necessary for locking purposes. The function will be resumed after checking the channel
174162 /// for data and will not wait for data to be available.
175163 pub async fn getOrNull(self: *SelfChannel) ?T {
176 // TODO fix this workaround
177 suspend {
178 resume @handle();
179 }
180
181164 // TODO integrate this function with named return values
182165 // so we can get rid of this extra result copy
183166 var result: ?T = null;
184 var my_tick_node = Loop.NextTickNode.init(@handle());
167 var my_tick_node = Loop.NextTickNode.init(@frame());
185168 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);
186169 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
187170 .tick_node = &my_tick_node,
......@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {
197180 // TODO test canceling getOrNull
198181 errdefer {
199182 _ = self.or_null_queue.remove(&or_null_node);
200 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
183 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
201184 const need_dispatch = !self.getters.remove(&queue_node);
202185 self.loop.cancelOnNextTick(&my_tick_node);
203186 if (need_dispatch) {
204187 // oops we made the get_count incorrect for a period of time. fix by dispatching.
205 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
188 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
206189 self.dispatch();
207190 }
208191 }
209192
210193 suspend {
211194 self.getters.put(&queue_node);
212 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
195 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
213196 self.or_null_queue.put(&or_null_node);
214197
215198 self.dispatch();
......@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {
219202
220203 fn dispatch(self: *SelfChannel) void {
221204 // set the "need dispatch" flag
222 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
205 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 1, .SeqCst);
223206
224207 lock: while (true) {
225208 // set the lock flag
226 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
209 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 1, .SeqCst);
227210 if (prev_lock != 0) return;
228211
229212 // clear the need_dispatch flag since we're about to do it
230 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
213 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
231214
232215 while (true) {
233216 one_dispatch: {
234217 // later we correct these extra subtractions
235 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
236 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
218 var get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
219 var put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
237220
238221 // transfer self.buffer to self.getters
239222 while (self.buffer_len != 0) {
......@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {
252235 self.loop.onNextTick(get_node.tick_node);
253236 self.buffer_len -= 1;
254237
255 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
238 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
256239 }
257240
258241 // direct transfer self.putters to self.getters
......@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {
272255 self.loop.onNextTick(get_node.tick_node);
273256 self.loop.onNextTick(put_node.tick_node);
274257
275 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
276 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
258 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
259 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
277260 }
278261
279262 // transfer self.putters to self.buffer
......@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {
285268 self.buffer_index +%= 1;
286269 self.buffer_len += 1;
287270
288 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
271 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
289272 }
290273 }
291274
292275 // undo the extra subtractions
293 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
294 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
276 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
277 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
295278
296279 // All the "get or null" functions should resume now.
297280 var remove_count: usize = 0;
......@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {
300283 self.loop.onNextTick(or_null_node.data.data.tick_node);
301284 }
302285 if (remove_count != 0) {
303 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, remove_count, AtomicOrder.SeqCst);
286 _ = @atomicRmw(usize, &self.get_count, .Sub, remove_count, .SeqCst);
304287 }
305288
306289 // clear need-dispatch flag
307 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
290 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
308291 if (need_dispatch != 0) continue;
309292
310 const my_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
293 const my_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 0, .SeqCst);
311294 assert(my_lock != 0);
312295
313296 // we have to check again now that we unlocked
314 if (@atomicLoad(u8, &self.need_dispatch, AtomicOrder.SeqCst) != 0) continue :lock;
297 if (@atomicLoad(u8, &self.need_dispatch, .SeqCst) != 0) continue :lock;
315298
316299 return;
317300 }
......@@ -324,51 +307,41 @@ test "std.event.Channel" {
324307 // https://github.com/ziglang/zig/issues/1908
325308 if (builtin.single_threaded) return error.SkipZigTest;
326309
327 const allocator = std.heap.direct_allocator;
328
329310 var loop: Loop = undefined;
330311 // TODO make a multi threaded test
331 try loop.initSingleThreaded(allocator);
312 try loop.initSingleThreaded(std.heap.direct_allocator);
332313 defer loop.deinit();
333314
334315 const channel = try Channel(i32).create(&loop, 0);
335316 defer channel.destroy();
336317
337 const handle = try async<allocator> testChannelGetter(&loop, channel);
338 defer cancel handle;
339
340 const putter = try async<allocator> testChannelPutter(channel);
341 defer cancel putter;
318 const handle = async testChannelGetter(&loop, channel);
319 const putter = async testChannelPutter(channel);
342320
343321 loop.run();
344322}
345323
346324async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
347 errdefer @panic("test failed");
348
349 const value1_promise = try async channel.get();
350 const value1 = await value1_promise;
325 const value1 = channel.get();
351326 testing.expect(value1 == 1234);
352327
353 const value2_promise = try async channel.get();
354 const value2 = await value2_promise;
328 const value2 = channel.get();
355329 testing.expect(value2 == 4567);
356330
357 const value3_promise = try async channel.getOrNull();
358 const value3 = await value3_promise;
331 const value3 = channel.getOrNull();
359332 testing.expect(value3 == null);
360333
361 const last_put = try async testPut(channel, 4444);
362 const value4 = await try async channel.getOrNull();
334 var last_put = async testPut(channel, 4444);
335 const value4 = channel.getOrNull();
363336 testing.expect(value4.? == 4444);
364337 await last_put;
365338}
366339
367340async fn testChannelPutter(channel: *Channel(i32)) void {
368 await (async channel.put(1234) catch @panic("out of memory"));
369 await (async channel.put(4567) catch @panic("out of memory"));
341 channel.put(1234);
342 channel.put(4567);
370343}
371344
372345async fn testPut(channel: *Channel(i32), value: i32) void {
373 await (async channel.put(value) catch @panic("out of memory"));
346 channel.put(value);
374347}
std/event/fs.zig+640-694
......@@ -76,17 +76,13 @@ pub const Request = struct {
7676
7777pub const PWriteVError = error{OutOfMemory} || File.WriteError;
7878
79/// data - just the inner references - must live until pwritev promise completes.
79/// data - just the inner references - must live until pwritev frame completes.
8080pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {
81 // workaround for https://github.com/ziglang/zig/issues/1194
82 suspend {
83 resume @handle();
84 }
8581 switch (builtin.os) {
86 builtin.Os.macosx,
87 builtin.Os.linux,
88 builtin.Os.freebsd,
89 builtin.Os.netbsd,
82 .macosx,
83 .linux,
84 .freebsd,
85 .netbsd,
9086 => {
9187 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
9288 defer loop.allocator.free(iovecs);
......@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
10096
10197 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);
10298 },
103 builtin.Os.windows => {
99 .windows => {
104100 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);
105101 defer loop.allocator.free(data_copy);
106102 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);
......@@ -109,7 +105,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
109105 }
110106}
111107
112/// data must outlive the returned promise
108/// data must outlive the returned frame
113109pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
114110 if (data.len == 0) return;
115111 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);
......@@ -123,15 +119,10 @@ pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, off
123119}
124120
125121pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {
126 // workaround for https://github.com/ziglang/zig/issues/1194
127 suspend {
128 resume @handle();
129 }
130
131122 var resume_node = Loop.ResumeNode.Basic{
132123 .base = Loop.ResumeNode{
133124 .id = Loop.ResumeNode.Id.Basic,
134 .handle = @handle(),
125 .handle = @frame(),
135126 .overlapped = windows.OVERLAPPED{
136127 .Internal = 0,
137128 .InternalHigh = 0,
......@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)
166157 }
167158}
168159
169/// iovecs must live until pwritev promise completes.
160/// iovecs must live until pwritev frame completes.
170161pub async fn pwritevPosix(
171162 loop: *Loop,
172163 fd: fd_t,
173164 iovecs: []const os.iovec_const,
174165 offset: usize,
175166) os.WriteError!void {
176 // workaround for https://github.com/ziglang/zig/issues/1194
177 suspend {
178 resume @handle();
179 }
180
181167 var req_node = RequestNode{
182168 .prev = null,
183169 .next = null,
......@@ -194,7 +180,7 @@ pub async fn pwritevPosix(
194180 .TickNode = Loop.NextTickNode{
195181 .prev = null,
196182 .next = null,
197 .data = @handle(),
183 .data = @frame(),
198184 },
199185 },
200186 },
......@@ -211,19 +197,14 @@ pub async fn pwritevPosix(
211197
212198pub const PReadVError = error{OutOfMemory} || File.ReadError;
213199
214/// data - just the inner references - must live until preadv promise completes.
200/// data - just the inner references - must live until preadv frame completes.
215201pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {
216 // workaround for https://github.com/ziglang/zig/issues/1194
217 suspend {
218 resume @handle();
219 }
220
221202 assert(data.len != 0);
222203 switch (builtin.os) {
223 builtin.Os.macosx,
224 builtin.Os.linux,
225 builtin.Os.freebsd,
226 builtin.Os.netbsd,
204 .macosx,
205 .linux,
206 .freebsd,
207 .netbsd,
227208 => {
228209 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229210 defer loop.allocator.free(iovecs);
......@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
237218
238219 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);
239220 },
240 builtin.Os.windows => {
221 .windows => {
241222 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);
242223 defer loop.allocator.free(data_copy);
243224 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);
......@@ -246,7 +227,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
246227 }
247228}
248229
249/// data must outlive the returned promise
230/// data must outlive the returned frame
250231pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
251232 assert(data.len != 0);
252233 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);
......@@ -272,15 +253,10 @@ pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u6
272253}
273254
274255pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {
275 // workaround for https://github.com/ziglang/zig/issues/1194
276 suspend {
277 resume @handle();
278 }
279
280256 var resume_node = Loop.ResumeNode.Basic{
281257 .base = Loop.ResumeNode{
282258 .id = Loop.ResumeNode.Id.Basic,
283 .handle = @handle(),
259 .handle = @frame(),
284260 .overlapped = windows.OVERLAPPED{
285261 .Internal = 0,
286262 .InternalHigh = 0,
......@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize
314290 return usize(bytes_transferred);
315291}
316292
317/// iovecs must live until preadv promise completes
293/// iovecs must live until preadv frame completes
318294pub async fn preadvPosix(
319295 loop: *Loop,
320296 fd: fd_t,
321297 iovecs: []const os.iovec,
322298 offset: usize,
323299) os.ReadError!usize {
324 // workaround for https://github.com/ziglang/zig/issues/1194
325 suspend {
326 resume @handle();
327 }
328
329300 var req_node = RequestNode{
330301 .prev = null,
331302 .next = null,
......@@ -342,7 +313,7 @@ pub async fn preadvPosix(
342313 .TickNode = Loop.NextTickNode{
343314 .prev = null,
344315 .next = null,
345 .data = @handle(),
316 .data = @frame(),
346317 },
347318 },
348319 },
......@@ -363,11 +334,6 @@ pub async fn openPosix(
363334 flags: u32,
364335 mode: File.Mode,
365336) File.OpenError!fd_t {
366 // workaround for https://github.com/ziglang/zig/issues/1194
367 suspend {
368 resume @handle();
369 }
370
371337 const path_c = try std.os.toPosixPath(path);
372338
373339 var req_node = RequestNode{
......@@ -386,7 +352,7 @@ pub async fn openPosix(
386352 .TickNode = Loop.NextTickNode{
387353 .prev = null,
388354 .next = null,
389 .data = @handle(),
355 .data = @frame(),
390356 },
391357 },
392358 },
......@@ -403,12 +369,12 @@ pub async fn openPosix(
403369
404370pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
405371 switch (builtin.os) {
406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
372 .macosx, .linux, .freebsd, .netbsd => {
407373 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
408374 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
409375 },
410376
411 builtin.Os.windows => return windows.CreateFile(
377 .windows => return windows.CreateFile(
412378 path,
413379 windows.GENERIC_READ,
414380 windows.FILE_SHARE_READ,
......@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
431397/// Creates if does not exist. Truncates the file if it exists.
432398pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
433399 switch (builtin.os) {
434 builtin.Os.macosx,
435 builtin.Os.linux,
436 builtin.Os.freebsd,
437 builtin.Os.netbsd,
400 .macosx,
401 .linux,
402 .freebsd,
403 .netbsd,
438404 => {
439405 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
440406 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
441407 },
442 builtin.Os.windows => return windows.CreateFile(
408 .windows => return windows.CreateFile(
443409 path,
444410 windows.GENERIC_WRITE,
445411 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
......@@ -459,12 +425,12 @@ pub async fn openReadWrite(
459425 mode: File.Mode,
460426) File.OpenError!fd_t {
461427 switch (builtin.os) {
462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
428 .macosx, .linux, .freebsd, .netbsd => {
463429 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
464430 return await (async openPosix(loop, path, flags, mode) catch unreachable);
465431 },
466432
467 builtin.Os.windows => return windows.CreateFile(
433 .windows => return windows.CreateFile(
468434 path,
469435 windows.GENERIC_WRITE | windows.GENERIC_READ,
470436 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
......@@ -489,9 +455,9 @@ pub const CloseOperation = struct {
489455 os_data: OsData,
490456
491457 const OsData = switch (builtin.os) {
492 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
458 .linux, .macosx, .freebsd, .netbsd => OsDataPosix,
493459
494 builtin.Os.windows => struct {
460 .windows => struct {
495461 handle: ?fd_t,
496462 },
497463
......@@ -508,8 +474,8 @@ pub const CloseOperation = struct {
508474 self.* = CloseOperation{
509475 .loop = loop,
510476 .os_data = switch (builtin.os) {
511 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),
512 builtin.Os.windows => OsData{ .handle = null },
477 .linux, .macosx, .freebsd, .netbsd => initOsDataPosix(self),
478 .windows => OsData{ .handle = null },
513479 else => @compileError("Unsupported OS"),
514480 },
515481 };
......@@ -535,10 +501,10 @@ pub const CloseOperation = struct {
535501 /// Defer this after creating.
536502 pub fn finish(self: *CloseOperation) void {
537503 switch (builtin.os) {
538 builtin.Os.linux,
539 builtin.Os.macosx,
540 builtin.Os.freebsd,
541 builtin.Os.netbsd,
504 .linux,
505 .macosx,
506 .freebsd,
507 .netbsd,
542508 => {
543509 if (self.os_data.have_fd) {
544510 self.loop.posixFsRequest(&self.os_data.close_req_node);
......@@ -546,7 +512,7 @@ pub const CloseOperation = struct {
546512 self.loop.allocator.destroy(self);
547513 }
548514 },
549 builtin.Os.windows => {
515 .windows => {
550516 if (self.os_data.handle) |handle| {
551517 os.close(handle);
552518 }
......@@ -558,15 +524,15 @@ pub const CloseOperation = struct {
558524
559525 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
560526 switch (builtin.os) {
561 builtin.Os.linux,
562 builtin.Os.macosx,
563 builtin.Os.freebsd,
564 builtin.Os.netbsd,
527 .linux,
528 .macosx,
529 .freebsd,
530 .netbsd,
565531 => {
566532 self.os_data.close_req_node.data.msg.Close.fd = handle;
567533 self.os_data.have_fd = true;
568534 },
569 builtin.Os.windows => {
535 .windows => {
570536 self.os_data.handle = handle;
571537 },
572538 else => @compileError("Unsupported OS"),
......@@ -576,14 +542,14 @@ pub const CloseOperation = struct {
576542 /// Undo a `setHandle`.
577543 pub fn clearHandle(self: *CloseOperation) void {
578544 switch (builtin.os) {
579 builtin.Os.linux,
580 builtin.Os.macosx,
581 builtin.Os.freebsd,
582 builtin.Os.netbsd,
545 .linux,
546 .macosx,
547 .freebsd,
548 .netbsd,
583549 => {
584550 self.os_data.have_fd = false;
585551 },
586 builtin.Os.windows => {
552 .windows => {
587553 self.os_data.handle = null;
588554 },
589555 else => @compileError("Unsupported OS"),
......@@ -592,15 +558,15 @@ pub const CloseOperation = struct {
592558
593559 pub fn getHandle(self: *CloseOperation) fd_t {
594560 switch (builtin.os) {
595 builtin.Os.linux,
596 builtin.Os.macosx,
597 builtin.Os.freebsd,
598 builtin.Os.netbsd,
561 .linux,
562 .macosx,
563 .freebsd,
564 .netbsd,
599565 => {
600566 assert(self.os_data.have_fd);
601567 return self.os_data.close_req_node.data.msg.Close.fd;
602568 },
603 builtin.Os.windows => {
569 .windows => {
604570 return self.os_data.handle.?;
605571 },
606572 else => @compileError("Unsupported OS"),
......@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi
617583/// contents must remain alive until writeFile completes.
618584pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
619585 switch (builtin.os) {
620 builtin.Os.linux,
621 builtin.Os.macosx,
622 builtin.Os.freebsd,
623 builtin.Os.netbsd,
586 .linux,
587 .macosx,
588 .freebsd,
589 .netbsd,
624590 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
625 builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
591 .windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
626592 else => @compileError("Unsupported OS"),
627593 }
628594}
......@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !
643609}
644610
645611async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
646 // workaround for https://github.com/ziglang/zig/issues/1194
647 suspend {
648 resume @handle();
649 }
650
651612 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);
652613 defer loop.allocator.free(path_with_null);
653614
......@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
667628 .TickNode = Loop.NextTickNode{
668629 .prev = null,
669630 .next = null,
670 .data = @handle(),
631 .data = @frame(),
671632 },
672633 },
673634 },
......@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
682643 return req_node.data.msg.WriteFile.result;
683644}
684645
685/// The promise resumes when the last data has been confirmed written, but before the file handle
646/// The frame resumes when the last data has been confirmed written, but before the file handle
686647/// is closed.
687648/// Caller owns returned memory.
688649pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {
......@@ -715,598 +676,583 @@ pub const WatchEventId = enum {
715676 Delete,
716677};
717678
718pub const WatchEventError = error{
719 UserResourceLimitReached,
720 SystemResources,
721 AccessDenied,
722 Unexpected, // TODO remove this possibility
723};
724
725pub fn Watch(comptime V: type) type {
726 return struct {
727 channel: *event.Channel(Event.Error!Event),
728 os_data: OsData,
729
730 const OsData = switch (builtin.os) {
731 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {
732 file_table: FileTable,
733 table_lock: event.Lock,
734
735 const FileTable = std.AutoHashMap([]const u8, *Put);
736 const Put = struct {
737 putter: promise,
738 value_ptr: *V,
739 };
740 },
741
742 builtin.Os.linux => LinuxOsData,
743 builtin.Os.windows => WindowsOsData,
744
745 else => @compileError("Unsupported OS"),
746 };
747
748 const WindowsOsData = struct {
749 table_lock: event.Lock,
750 dir_table: DirTable,
751 all_putters: std.atomic.Queue(promise),
752 ref_count: std.atomic.Int(usize),
753
754 const DirTable = std.AutoHashMap([]const u8, *Dir);
755 const FileTable = std.AutoHashMap([]const u16, V);
756
757 const Dir = struct {
758 putter: promise,
759 file_table: FileTable,
760 table_lock: event.Lock,
761 };
762 };
763
764 const LinuxOsData = struct {
765 putter: promise,
766 inotify_fd: i32,
767 wd_table: WdTable,
768 table_lock: event.Lock,
769
770 const WdTable = std.AutoHashMap(i32, Dir);
771 const FileTable = std.AutoHashMap([]const u8, V);
772
773 const Dir = struct {
774 dirname: []const u8,
775 file_table: FileTable,
776 };
777 };
778
779 const FileToHandle = std.AutoHashMap([]const u8, promise);
780
781 const Self = @This();
782
783 pub const Event = struct {
784 id: Id,
785 data: V,
786
787 pub const Id = WatchEventId;
788 pub const Error = WatchEventError;
789 };
790
791 pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
792 const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
793 errdefer channel.destroy();
794
795 switch (builtin.os) {
796 builtin.Os.linux => {
797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
798 errdefer os.close(inotify_fd);
799
800 var result: *Self = undefined;
801 _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
802 return result;
803 },
804
805 builtin.Os.windows => {
806 const self = try loop.allocator.create(Self);
807 errdefer loop.allocator.destroy(self);
808 self.* = Self{
809 .channel = channel,
810 .os_data = OsData{
811 .table_lock = event.Lock.init(loop),
812 .dir_table = OsData.DirTable.init(loop.allocator),
813 .ref_count = std.atomic.Int(usize).init(1),
814 .all_putters = std.atomic.Queue(promise).init(),
815 },
816 };
817 return self;
818 },
819
820 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
821 const self = try loop.allocator.create(Self);
822 errdefer loop.allocator.destroy(self);
823
824 self.* = Self{
825 .channel = channel,
826 .os_data = OsData{
827 .table_lock = event.Lock.init(loop),
828 .file_table = OsData.FileTable.init(loop.allocator),
829 },
830 };
831 return self;
832 },
833 else => @compileError("Unsupported OS"),
834 }
835 }
836
837 /// All addFile calls and removeFile calls must have completed.
838 pub fn destroy(self: *Self) void {
839 switch (builtin.os) {
840 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
841 // TODO we need to cancel the coroutines before destroying the lock
842 self.os_data.table_lock.deinit();
843 var it = self.os_data.file_table.iterator();
844 while (it.next()) |entry| {
845 cancel entry.value.putter;
846 self.channel.loop.allocator.free(entry.key);
847 }
848 self.channel.destroy();
849 },
850 builtin.Os.linux => cancel self.os_data.putter,
851 builtin.Os.windows => {
852 while (self.os_data.all_putters.get()) |putter_node| {
853 cancel putter_node.data;
854 }
855 self.deref();
856 },
857 else => @compileError("Unsupported OS"),
858 }
859 }
860
861 fn ref(self: *Self) void {
862 _ = self.os_data.ref_count.incr();
863 }
864
865 fn deref(self: *Self) void {
866 if (self.os_data.ref_count.decr() == 1) {
867 const allocator = self.channel.loop.allocator;
868 self.os_data.table_lock.deinit();
869 var it = self.os_data.dir_table.iterator();
870 while (it.next()) |entry| {
871 allocator.free(entry.key);
872 allocator.destroy(entry.value);
873 }
874 self.os_data.dir_table.deinit();
875 self.channel.destroy();
876 allocator.destroy(self);
877 }
878 }
879
880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
881 switch (builtin.os) {
882 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),
886 }
887 }
888
889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891 var resolved_path_consumed = false;
892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893
894 var close_op = try CloseOperation.start(self.channel.loop);
895 var close_op_consumed = false;
896 defer if (!close_op_consumed) close_op.finish();
897
898 const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
899 const mode = 0;
900 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
901 close_op.setHandle(fd);
902
903 var put_data: *OsData.Put = undefined;
904 const putter = try async self.kqPutEvents(close_op, value, &put_data);
905 close_op_consumed = true;
906 errdefer cancel putter;
907
908 const result = blk: {
909 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
910 defer held.release();
911
912 const gop = try self.os_data.file_table.getOrPut(resolved_path);
913 if (gop.found_existing) {
914 const prev_value = gop.kv.value.value_ptr.*;
915 cancel gop.kv.value.putter;
916 gop.kv.value = put_data;
917 break :blk prev_value;
918 } else {
919 resolved_path_consumed = true;
920 gop.kv.value = put_data;
921 break :blk null;
922 }
923 };
924
925 return result;
926 }
927
928 async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
929 // TODO https://github.com/ziglang/zig/issues/1194
930 suspend {
931 resume @handle();
932 }
933
934 var value_copy = value;
935 var put = OsData.Put{
936 .putter = @handle(),
937 .value_ptr = &value_copy,
938 };
939 out_put.* = &put;
940 self.channel.loop.beginOneEvent();
941
942 defer {
943 close_op.finish();
944 self.channel.loop.finishOneEvent();
945 }
946
947 while (true) {
948 if (await (async self.channel.loop.bsdWaitKev(
949 @intCast(usize, close_op.getHandle()),
950 os.EVFILT_VNODE,
951 os.NOTE_WRITE | os.NOTE_DELETE,
952 ) catch unreachable)) |kev| {
953 // TODO handle EV_ERROR
954 if (kev.fflags & os.NOTE_DELETE != 0) {
955 await (async self.channel.put(Self.Event{
956 .id = Event.Id.Delete,
957 .data = value_copy,
958 }) catch unreachable);
959 } else if (kev.fflags & os.NOTE_WRITE != 0) {
960 await (async self.channel.put(Self.Event{
961 .id = Event.Id.CloseWrite,
962 .data = value_copy,
963 }) catch unreachable);
964 }
965 } else |err| switch (err) {
966 error.EventNotFound => unreachable,
967 error.ProcessNotFound => unreachable,
968 error.Overflow => unreachable,
969 error.AccessDenied, error.SystemResources => |casted_err| {
970 await (async self.channel.put(casted_err) catch unreachable);
971 },
972 }
973 }
974 }
975
976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
977 const value_copy = value;
978
979 const dirname = std.fs.path.dirname(file_path) orelse ".";
980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
981 var dirname_with_null_consumed = false;
982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
983
984 const basename = std.fs.path.basename(file_path);
985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
986 var basename_with_null_consumed = false;
987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
988
989 const wd = try os.inotify_add_watchC(
990 self.os_data.inotify_fd,
991 dirname_with_null.ptr,
992 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
993 );
994 // wd is either a newly created watch or an existing one.
995
996 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
997 defer held.release();
998
999 const gop = try self.os_data.wd_table.getOrPut(wd);
1000 if (!gop.found_existing) {
1001 gop.kv.value = OsData.Dir{
1002 .dirname = dirname_with_null,
1003 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1004 };
1005 dirname_with_null_consumed = true;
1006 }
1007 const dir = &gop.kv.value;
1008
1009 const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
1010 if (file_table_gop.found_existing) {
1011 const prev_value = file_table_gop.kv.value;
1012 file_table_gop.kv.value = value_copy;
1013 return prev_value;
1014 } else {
1015 file_table_gop.kv.value = value_copy;
1016 basename_with_null_consumed = true;
1017 return null;
1018 }
1019 }
1020
1021 async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
1022 const value_copy = value;
1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
1024
1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1026 var dirname_consumed = false;
1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
1028
1029 const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
1030 defer self.channel.loop.allocator.free(dirname_utf16le);
1031
1032 // TODO https://github.com/ziglang/zig/issues/265
1033 const basename = std.fs.path.basename(file_path);
1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1035 var basename_utf16le_null_consumed = false;
1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
1038
1039 const dir_handle = try windows.CreateFileW(
1040 dirname_utf16le.ptr,
1041 windows.FILE_LIST_DIRECTORY,
1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
1043 null,
1044 windows.OPEN_EXISTING,
1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1046 null,
1047 );
1048 var dir_handle_consumed = false;
1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1050
1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1052 defer held.release();
1053
1054 const gop = try self.os_data.dir_table.getOrPut(dirname);
1055 if (gop.found_existing) {
1056 const dir = gop.kv.value;
1057 const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
1058 defer held_dir_lock.release();
1059
1060 const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1061 if (file_gop.found_existing) {
1062 const prev_value = file_gop.kv.value;
1063 file_gop.kv.value = value_copy;
1064 return prev_value;
1065 } else {
1066 file_gop.kv.value = value_copy;
1067 basename_utf16le_null_consumed = true;
1068 return null;
1069 }
1070 } else {
1071 errdefer _ = self.os_data.dir_table.remove(dirname);
1072 const dir = try self.channel.loop.allocator.create(OsData.Dir);
1073 errdefer self.channel.loop.allocator.destroy(dir);
1074
1075 dir.* = OsData.Dir{
1076 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1077 .table_lock = event.Lock.init(self.channel.loop),
1078 .putter = undefined,
1079 };
1080 gop.kv.value = dir;
1081 assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1082 basename_utf16le_null_consumed = true;
1083
1084 dir.putter = try async self.windowsDirReader(dir_handle, dir);
1085 dir_handle_consumed = true;
1086
1087 dirname_consumed = true;
1088
1089 return null;
1090 }
1091 }
1092
1093 async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1094 // TODO https://github.com/ziglang/zig/issues/1194
1095 suspend {
1096 resume @handle();
1097 }
1098
1099 self.ref();
1100 defer self.deref();
1101
1102 defer os.close(dir_handle);
1103
1104 var putter_node = std.atomic.Queue(promise).Node{
1105 .data = @handle(),
1106 .prev = null,
1107 .next = null,
1108 };
1109 self.os_data.all_putters.put(&putter_node);
1110 defer _ = self.os_data.all_putters.remove(&putter_node);
1111
1112 var resume_node = Loop.ResumeNode.Basic{
1113 .base = Loop.ResumeNode{
1114 .id = Loop.ResumeNode.Id.Basic,
1115 .handle = @handle(),
1116 .overlapped = windows.OVERLAPPED{
1117 .Internal = 0,
1118 .InternalHigh = 0,
1119 .Offset = 0,
1120 .OffsetHigh = 0,
1121 .hEvent = null,
1122 },
1123 },
1124 };
1125 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1126
1127 // TODO handle this error not in the channel but in the setup
1128 _ = windows.CreateIoCompletionPort(
1129 dir_handle,
1130 self.channel.loop.os_data.io_port,
1131 undefined,
1132 undefined,
1133 ) catch |err| {
1134 await (async self.channel.put(err) catch unreachable);
1135 return;
1136 };
1137
1138 while (true) {
1139 {
1140 // TODO only 1 beginOneEvent for the whole coroutine
1141 self.channel.loop.beginOneEvent();
1142 errdefer self.channel.loop.finishOneEvent();
1143 errdefer {
1144 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1145 }
1146 suspend {
1147 _ = windows.kernel32.ReadDirectoryChangesW(
1148 dir_handle,
1149 &event_buf,
1150 @intCast(windows.DWORD, event_buf.len),
1151 windows.FALSE, // watch subtree
1152 windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1153 windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1154 windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1155 windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1156 null, // number of bytes transferred (unused for async)
1157 &resume_node.base.overlapped,
1158 null, // completion routine - unused because we use IOCP
1159 );
1160 }
1161 }
1162 var bytes_transferred: windows.DWORD = undefined;
1163 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1164 const err = switch (windows.kernel32.GetLastError()) {
1165 else => |err| windows.unexpectedError(err),
1166 };
1167 await (async self.channel.put(err) catch unreachable);
1168 } else {
1169 // can't use @bytesToSlice because of the special variable length name field
1170 var ptr = event_buf[0..].ptr;
1171 const end_ptr = ptr + bytes_transferred;
1172 var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1173 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1174 ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1175 const emit = switch (ev.Action) {
1176 windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1177 windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1178 else => null,
1179 };
1180 if (emit) |id| {
1181 const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1182 const user_value = blk: {
1183 const held = await (async dir.table_lock.acquire() catch unreachable);
1184 defer held.release();
1185
1186 if (dir.file_table.get(basename_utf16le)) |entry| {
1187 break :blk entry.value;
1188 } else {
1189 break :blk null;
1190 }
1191 };
1192 if (user_value) |v| {
1193 await (async self.channel.put(Event{
1194 .id = id,
1195 .data = v,
1196 }) catch unreachable);
1197 }
1198 }
1199 if (ev.NextEntryOffset == 0) break;
1200 }
1201 }
1202 }
1203 }
1204
1205 pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1206 @panic("TODO");
1207 }
1208
1209 async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1210 // TODO https://github.com/ziglang/zig/issues/1194
1211 suspend {
1212 resume @handle();
1213 }
1214
1215 const loop = channel.loop;
1216
1217 var watch = Self{
1218 .channel = channel,
1219 .os_data = OsData{
1220 .putter = @handle(),
1221 .inotify_fd = inotify_fd,
1222 .wd_table = OsData.WdTable.init(loop.allocator),
1223 .table_lock = event.Lock.init(loop),
1224 },
1225 };
1226 out_watch.* = &watch;
1227
1228 loop.beginOneEvent();
1229
1230 defer {
1231 watch.os_data.table_lock.deinit();
1232 var wd_it = watch.os_data.wd_table.iterator();
1233 while (wd_it.next()) |wd_entry| {
1234 var file_it = wd_entry.value.file_table.iterator();
1235 while (file_it.next()) |file_entry| {
1236 loop.allocator.free(file_entry.key);
1237 }
1238 loop.allocator.free(wd_entry.value.dirname);
1239 }
1240 loop.finishOneEvent();
1241 os.close(inotify_fd);
1242 channel.destroy();
1243 }
1244
1245 var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1246
1247 while (true) {
1248 const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1249 const errno = os.linux.getErrno(rc);
1250 switch (errno) {
1251 0 => {
1252 // can't use @bytesToSlice because of the special variable length name field
1253 var ptr = event_buf[0..].ptr;
1254 const end_ptr = ptr + event_buf.len;
1255 var ev: *os.linux.inotify_event = undefined;
1256 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1257 ev = @ptrCast(*os.linux.inotify_event, ptr);
1258 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1259 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1260 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1261 const user_value = blk: {
1262 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1263 defer held.release();
1264
1265 const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1266 if (dir.file_table.get(basename_with_null)) |entry| {
1267 break :blk entry.value;
1268 } else {
1269 break :blk null;
1270 }
1271 };
1272 if (user_value) |v| {
1273 await (async channel.put(Event{
1274 .id = WatchEventId.CloseWrite,
1275 .data = v,
1276 }) catch unreachable);
1277 }
1278 }
1279 }
1280 },
1281 os.linux.EINTR => continue,
1282 os.linux.EINVAL => unreachable,
1283 os.linux.EFAULT => unreachable,
1284 os.linux.EAGAIN => {
1285 (await (async loop.linuxWaitFd(
1286 inotify_fd,
1287 os.linux.EPOLLET | os.linux.EPOLLIN,
1288 ) catch unreachable)) catch |err| {
1289 const transformed_err = switch (err) {
1290 error.FileDescriptorAlreadyPresentInSet => unreachable,
1291 error.OperationCausesCircularLoop => unreachable,
1292 error.FileDescriptorNotRegistered => unreachable,
1293 error.FileDescriptorIncompatibleWithEpoll => unreachable,
1294 error.Unexpected => unreachable,
1295 else => |e| e,
1296 };
1297 await (async channel.put(transformed_err) catch unreachable);
1298 };
1299 },
1300 else => unreachable,
1301 }
1302 }
1303 }
1304 };
1305}
679//pub const WatchEventError = error{
680// UserResourceLimitReached,
681// SystemResources,
682// AccessDenied,
683// Unexpected, // TODO remove this possibility
684//};
685//
686//pub fn Watch(comptime V: type) type {
687// return struct {
688// channel: *event.Channel(Event.Error!Event),
689// os_data: OsData,
690//
691// const OsData = switch (builtin.os) {
692// .macosx, .freebsd, .netbsd => struct {
693// file_table: FileTable,
694// table_lock: event.Lock,
695//
696// const FileTable = std.AutoHashMap([]const u8, *Put);
697// const Put = struct {
698// putter: anyframe,
699// value_ptr: *V,
700// };
701// },
702//
703// .linux => LinuxOsData,
704// .windows => WindowsOsData,
705//
706// else => @compileError("Unsupported OS"),
707// };
708//
709// const WindowsOsData = struct {
710// table_lock: event.Lock,
711// dir_table: DirTable,
712// all_putters: std.atomic.Queue(anyframe),
713// ref_count: std.atomic.Int(usize),
714//
715// const DirTable = std.AutoHashMap([]const u8, *Dir);
716// const FileTable = std.AutoHashMap([]const u16, V);
717//
718// const Dir = struct {
719// putter: anyframe,
720// file_table: FileTable,
721// table_lock: event.Lock,
722// };
723// };
724//
725// const LinuxOsData = struct {
726// putter: anyframe,
727// inotify_fd: i32,
728// wd_table: WdTable,
729// table_lock: event.Lock,
730//
731// const WdTable = std.AutoHashMap(i32, Dir);
732// const FileTable = std.AutoHashMap([]const u8, V);
733//
734// const Dir = struct {
735// dirname: []const u8,
736// file_table: FileTable,
737// };
738// };
739//
740// const FileToHandle = std.AutoHashMap([]const u8, anyframe);
741//
742// const Self = @This();
743//
744// pub const Event = struct {
745// id: Id,
746// data: V,
747//
748// pub const Id = WatchEventId;
749// pub const Error = WatchEventError;
750// };
751//
752// pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
753// const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
754// errdefer channel.destroy();
755//
756// switch (builtin.os) {
757// .linux => {
758// const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
759// errdefer os.close(inotify_fd);
760//
761// var result: *Self = undefined;
762// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
763// return result;
764// },
765//
766// .windows => {
767// const self = try loop.allocator.create(Self);
768// errdefer loop.allocator.destroy(self);
769// self.* = Self{
770// .channel = channel,
771// .os_data = OsData{
772// .table_lock = event.Lock.init(loop),
773// .dir_table = OsData.DirTable.init(loop.allocator),
774// .ref_count = std.atomic.Int(usize).init(1),
775// .all_putters = std.atomic.Queue(anyframe).init(),
776// },
777// };
778// return self;
779// },
780//
781// .macosx, .freebsd, .netbsd => {
782// const self = try loop.allocator.create(Self);
783// errdefer loop.allocator.destroy(self);
784//
785// self.* = Self{
786// .channel = channel,
787// .os_data = OsData{
788// .table_lock = event.Lock.init(loop),
789// .file_table = OsData.FileTable.init(loop.allocator),
790// },
791// };
792// return self;
793// },
794// else => @compileError("Unsupported OS"),
795// }
796// }
797//
798// /// All addFile calls and removeFile calls must have completed.
799// pub fn destroy(self: *Self) void {
800// switch (builtin.os) {
801// .macosx, .freebsd, .netbsd => {
802// // TODO we need to cancel the frames before destroying the lock
803// self.os_data.table_lock.deinit();
804// var it = self.os_data.file_table.iterator();
805// while (it.next()) |entry| {
806// cancel entry.value.putter;
807// self.channel.loop.allocator.free(entry.key);
808// }
809// self.channel.destroy();
810// },
811// .linux => cancel self.os_data.putter,
812// .windows => {
813// while (self.os_data.all_putters.get()) |putter_node| {
814// cancel putter_node.data;
815// }
816// self.deref();
817// },
818// else => @compileError("Unsupported OS"),
819// }
820// }
821//
822// fn ref(self: *Self) void {
823// _ = self.os_data.ref_count.incr();
824// }
825//
826// fn deref(self: *Self) void {
827// if (self.os_data.ref_count.decr() == 1) {
828// const allocator = self.channel.loop.allocator;
829// self.os_data.table_lock.deinit();
830// var it = self.os_data.dir_table.iterator();
831// while (it.next()) |entry| {
832// allocator.free(entry.key);
833// allocator.destroy(entry.value);
834// }
835// self.os_data.dir_table.deinit();
836// self.channel.destroy();
837// allocator.destroy(self);
838// }
839// }
840//
841// pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
842// switch (builtin.os) {
843// .macosx, .freebsd, .netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
844// .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
845// .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
846// else => @compileError("Unsupported OS"),
847// }
848// }
849//
850// async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
851// const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
852// var resolved_path_consumed = false;
853// defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
854//
855// var close_op = try CloseOperation.start(self.channel.loop);
856// var close_op_consumed = false;
857// defer if (!close_op_consumed) close_op.finish();
858//
859// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
860// const mode = 0;
861// const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
862// close_op.setHandle(fd);
863//
864// var put_data: *OsData.Put = undefined;
865// const putter = try async self.kqPutEvents(close_op, value, &put_data);
866// close_op_consumed = true;
867// errdefer cancel putter;
868//
869// const result = blk: {
870// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
871// defer held.release();
872//
873// const gop = try self.os_data.file_table.getOrPut(resolved_path);
874// if (gop.found_existing) {
875// const prev_value = gop.kv.value.value_ptr.*;
876// cancel gop.kv.value.putter;
877// gop.kv.value = put_data;
878// break :blk prev_value;
879// } else {
880// resolved_path_consumed = true;
881// gop.kv.value = put_data;
882// break :blk null;
883// }
884// };
885//
886// return result;
887// }
888//
889// async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
890// var value_copy = value;
891// var put = OsData.Put{
892// .putter = @frame(),
893// .value_ptr = &value_copy,
894// };
895// out_put.* = &put;
896// self.channel.loop.beginOneEvent();
897//
898// defer {
899// close_op.finish();
900// self.channel.loop.finishOneEvent();
901// }
902//
903// while (true) {
904// if (await (async self.channel.loop.bsdWaitKev(
905// @intCast(usize, close_op.getHandle()),
906// os.EVFILT_VNODE,
907// os.NOTE_WRITE | os.NOTE_DELETE,
908// ) catch unreachable)) |kev| {
909// // TODO handle EV_ERROR
910// if (kev.fflags & os.NOTE_DELETE != 0) {
911// await (async self.channel.put(Self.Event{
912// .id = Event.Id.Delete,
913// .data = value_copy,
914// }) catch unreachable);
915// } else if (kev.fflags & os.NOTE_WRITE != 0) {
916// await (async self.channel.put(Self.Event{
917// .id = Event.Id.CloseWrite,
918// .data = value_copy,
919// }) catch unreachable);
920// }
921// } else |err| switch (err) {
922// error.EventNotFound => unreachable,
923// error.ProcessNotFound => unreachable,
924// error.Overflow => unreachable,
925// error.AccessDenied, error.SystemResources => |casted_err| {
926// await (async self.channel.put(casted_err) catch unreachable);
927// },
928// }
929// }
930// }
931//
932// async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
933// const value_copy = value;
934//
935// const dirname = std.fs.path.dirname(file_path) orelse ".";
936// const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
937// var dirname_with_null_consumed = false;
938// defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
939//
940// const basename = std.fs.path.basename(file_path);
941// const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
942// var basename_with_null_consumed = false;
943// defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
944//
945// const wd = try os.inotify_add_watchC(
946// self.os_data.inotify_fd,
947// dirname_with_null.ptr,
948// os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
949// );
950// // wd is either a newly created watch or an existing one.
951//
952// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
953// defer held.release();
954//
955// const gop = try self.os_data.wd_table.getOrPut(wd);
956// if (!gop.found_existing) {
957// gop.kv.value = OsData.Dir{
958// .dirname = dirname_with_null,
959// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
960// };
961// dirname_with_null_consumed = true;
962// }
963// const dir = &gop.kv.value;
964//
965// const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
966// if (file_table_gop.found_existing) {
967// const prev_value = file_table_gop.kv.value;
968// file_table_gop.kv.value = value_copy;
969// return prev_value;
970// } else {
971// file_table_gop.kv.value = value_copy;
972// basename_with_null_consumed = true;
973// return null;
974// }
975// }
976//
977// async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
978// const value_copy = value;
979// // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
980//
981// const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
982// var dirname_consumed = false;
983// defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
984//
985// const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
986// defer self.channel.loop.allocator.free(dirname_utf16le);
987//
988// // TODO https://github.com/ziglang/zig/issues/265
989// const basename = std.fs.path.basename(file_path);
990// const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
991// var basename_utf16le_null_consumed = false;
992// defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
993// const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
994//
995// const dir_handle = try windows.CreateFileW(
996// dirname_utf16le.ptr,
997// windows.FILE_LIST_DIRECTORY,
998// windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
999// null,
1000// windows.OPEN_EXISTING,
1001// windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1002// null,
1003// );
1004// var dir_handle_consumed = false;
1005// defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1006//
1007// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1008// defer held.release();
1009//
1010// const gop = try self.os_data.dir_table.getOrPut(dirname);
1011// if (gop.found_existing) {
1012// const dir = gop.kv.value;
1013// const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
1014// defer held_dir_lock.release();
1015//
1016// const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1017// if (file_gop.found_existing) {
1018// const prev_value = file_gop.kv.value;
1019// file_gop.kv.value = value_copy;
1020// return prev_value;
1021// } else {
1022// file_gop.kv.value = value_copy;
1023// basename_utf16le_null_consumed = true;
1024// return null;
1025// }
1026// } else {
1027// errdefer _ = self.os_data.dir_table.remove(dirname);
1028// const dir = try self.channel.loop.allocator.create(OsData.Dir);
1029// errdefer self.channel.loop.allocator.destroy(dir);
1030//
1031// dir.* = OsData.Dir{
1032// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1033// .table_lock = event.Lock.init(self.channel.loop),
1034// .putter = undefined,
1035// };
1036// gop.kv.value = dir;
1037// assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1038// basename_utf16le_null_consumed = true;
1039//
1040// dir.putter = try async self.windowsDirReader(dir_handle, dir);
1041// dir_handle_consumed = true;
1042//
1043// dirname_consumed = true;
1044//
1045// return null;
1046// }
1047// }
1048//
1049// async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1050// self.ref();
1051// defer self.deref();
1052//
1053// defer os.close(dir_handle);
1054//
1055// var putter_node = std.atomic.Queue(anyframe).Node{
1056// .data = @frame(),
1057// .prev = null,
1058// .next = null,
1059// };
1060// self.os_data.all_putters.put(&putter_node);
1061// defer _ = self.os_data.all_putters.remove(&putter_node);
1062//
1063// var resume_node = Loop.ResumeNode.Basic{
1064// .base = Loop.ResumeNode{
1065// .id = Loop.ResumeNode.Id.Basic,
1066// .handle = @frame(),
1067// .overlapped = windows.OVERLAPPED{
1068// .Internal = 0,
1069// .InternalHigh = 0,
1070// .Offset = 0,
1071// .OffsetHigh = 0,
1072// .hEvent = null,
1073// },
1074// },
1075// };
1076// var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1077//
1078// // TODO handle this error not in the channel but in the setup
1079// _ = windows.CreateIoCompletionPort(
1080// dir_handle,
1081// self.channel.loop.os_data.io_port,
1082// undefined,
1083// undefined,
1084// ) catch |err| {
1085// await (async self.channel.put(err) catch unreachable);
1086// return;
1087// };
1088//
1089// while (true) {
1090// {
1091// // TODO only 1 beginOneEvent for the whole function
1092// self.channel.loop.beginOneEvent();
1093// errdefer self.channel.loop.finishOneEvent();
1094// errdefer {
1095// _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1096// }
1097// suspend {
1098// _ = windows.kernel32.ReadDirectoryChangesW(
1099// dir_handle,
1100// &event_buf,
1101// @intCast(windows.DWORD, event_buf.len),
1102// windows.FALSE, // watch subtree
1103// windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1104// windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1105// windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1106// windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1107// null, // number of bytes transferred (unused for async)
1108// &resume_node.base.overlapped,
1109// null, // completion routine - unused because we use IOCP
1110// );
1111// }
1112// }
1113// var bytes_transferred: windows.DWORD = undefined;
1114// if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1115// const err = switch (windows.kernel32.GetLastError()) {
1116// else => |err| windows.unexpectedError(err),
1117// };
1118// await (async self.channel.put(err) catch unreachable);
1119// } else {
1120// // can't use @bytesToSlice because of the special variable length name field
1121// var ptr = event_buf[0..].ptr;
1122// const end_ptr = ptr + bytes_transferred;
1123// var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1124// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1125// ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1126// const emit = switch (ev.Action) {
1127// windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1128// windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1129// else => null,
1130// };
1131// if (emit) |id| {
1132// const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1133// const user_value = blk: {
1134// const held = await (async dir.table_lock.acquire() catch unreachable);
1135// defer held.release();
1136//
1137// if (dir.file_table.get(basename_utf16le)) |entry| {
1138// break :blk entry.value;
1139// } else {
1140// break :blk null;
1141// }
1142// };
1143// if (user_value) |v| {
1144// await (async self.channel.put(Event{
1145// .id = id,
1146// .data = v,
1147// }) catch unreachable);
1148// }
1149// }
1150// if (ev.NextEntryOffset == 0) break;
1151// }
1152// }
1153// }
1154// }
1155//
1156// pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1157// @panic("TODO");
1158// }
1159//
1160// async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1161// const loop = channel.loop;
1162//
1163// var watch = Self{
1164// .channel = channel,
1165// .os_data = OsData{
1166// .putter = @frame(),
1167// .inotify_fd = inotify_fd,
1168// .wd_table = OsData.WdTable.init(loop.allocator),
1169// .table_lock = event.Lock.init(loop),
1170// },
1171// };
1172// out_watch.* = &watch;
1173//
1174// loop.beginOneEvent();
1175//
1176// defer {
1177// watch.os_data.table_lock.deinit();
1178// var wd_it = watch.os_data.wd_table.iterator();
1179// while (wd_it.next()) |wd_entry| {
1180// var file_it = wd_entry.value.file_table.iterator();
1181// while (file_it.next()) |file_entry| {
1182// loop.allocator.free(file_entry.key);
1183// }
1184// loop.allocator.free(wd_entry.value.dirname);
1185// }
1186// loop.finishOneEvent();
1187// os.close(inotify_fd);
1188// channel.destroy();
1189// }
1190//
1191// var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1192//
1193// while (true) {
1194// const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1195// const errno = os.linux.getErrno(rc);
1196// switch (errno) {
1197// 0 => {
1198// // can't use @bytesToSlice because of the special variable length name field
1199// var ptr = event_buf[0..].ptr;
1200// const end_ptr = ptr + event_buf.len;
1201// var ev: *os.linux.inotify_event = undefined;
1202// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1203// ev = @ptrCast(*os.linux.inotify_event, ptr);
1204// if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1205// const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1206// const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1207// const user_value = blk: {
1208// const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1209// defer held.release();
1210//
1211// const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1212// if (dir.file_table.get(basename_with_null)) |entry| {
1213// break :blk entry.value;
1214// } else {
1215// break :blk null;
1216// }
1217// };
1218// if (user_value) |v| {
1219// await (async channel.put(Event{
1220// .id = WatchEventId.CloseWrite,
1221// .data = v,
1222// }) catch unreachable);
1223// }
1224// }
1225// }
1226// },
1227// os.linux.EINTR => continue,
1228// os.linux.EINVAL => unreachable,
1229// os.linux.EFAULT => unreachable,
1230// os.linux.EAGAIN => {
1231// (await (async loop.linuxWaitFd(
1232// inotify_fd,
1233// os.linux.EPOLLET | os.linux.EPOLLIN,
1234// ) catch unreachable)) catch |err| {
1235// const transformed_err = switch (err) {
1236// error.FileDescriptorAlreadyPresentInSet => unreachable,
1237// error.OperationCausesCircularLoop => unreachable,
1238// error.FileDescriptorNotRegistered => unreachable,
1239// error.FileDescriptorIncompatibleWithEpoll => unreachable,
1240// error.Unexpected => unreachable,
1241// else => |e| e,
1242// };
1243// await (async channel.put(transformed_err) catch unreachable);
1244// };
1245// },
1246// else => unreachable,
1247// }
1248// }
1249// }
1250// };
1251//}
13061252
13071253const test_tmp_dir = "std_event_fs_test";
13081254
1309// TODO this test is disabled until the coroutine rewrite is finished.
1255// TODO this test is disabled until the async function rewrite is finished.
13101256//test "write a file, watch it, write it again" {
13111257// return error.SkipZigTest;
13121258// const allocator = std.heap.direct_allocator;
......@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {
13551301
13561302 const ev = try async watch.channel.get();
13571303 var ev_consumed = false;
1358 defer if (!ev_consumed) cancel ev;
1304 defer if (!ev_consumed) await ev;
13591305
13601306 // overwrite line 2
13611307 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
......@@ -1397,11 +1343,11 @@ pub const OutStream = struct {
13971343 };
13981344 }
13991345
1400 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
1346 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
14011347 const self = @fieldParentPtr(OutStream, "stream", out_stream);
14021348 const offset = self.offset;
14031349 self.offset += bytes.len;
1404 return await (async pwritev(self.loop, self.fd, [][]const u8{bytes}, offset) catch unreachable);
1350 return pwritev(self.loop, self.fd, [][]const u8{bytes}, offset);
14051351 }
14061352};
14071353
......@@ -1423,9 +1369,9 @@ pub const InStream = struct {
14231369 };
14241370 }
14251371
1426 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
1372 fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
14271373 const self = @fieldParentPtr(InStream, "stream", in_stream);
1428 const amt = try await (async preadv(self.loop, self.fd, [][]u8{bytes}, self.offset) catch unreachable);
1374 const amt = try preadv(self.loop, self.fd, [][]u8{bytes}, self.offset);
14291375 self.offset += amt;
14301376 return amt;
14311377 }
std/event/future.zig+21-28
......@@ -2,13 +2,11 @@ const std = @import("../std.zig");
22const assert = std.debug.assert;
33const testing = std.testing;
44const builtin = @import("builtin");
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const Lock = std.event.Lock;
86const Loop = std.event.Loop;
97
108/// This is a value that starts out unavailable, until resolve() is called
11/// While it is unavailable, coroutines suspend when they try to get() it,
9/// While it is unavailable, functions suspend when they try to get() it,
1210/// and then are resumed when resolve() is called.
1311/// At this point the value remains forever available, and another resolve() is not allowed.
1412pub fn Future(comptime T: type) type {
......@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {
2321 available: u8,
2422
2523 const Self = @This();
26 const Queue = std.atomic.Queue(promise);
24 const Queue = std.atomic.Queue(anyframe);
2725
2826 pub fn init(loop: *Loop) Self {
2927 return Self{
......@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {
3735 /// available.
3836 /// Thread-safe.
3937 pub async fn get(self: *Self) *T {
40 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
38 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
4139 return &self.data;
4240 }
43 const held = await (async self.lock.acquire() catch unreachable);
41 const held = self.lock.acquire();
4442 held.release();
4543
4644 return &self.data;
......@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {
4947 /// Gets the data without waiting for it. If it's available, a pointer is
5048 /// returned. Otherwise, null is returned.
5149 pub fn getOrNull(self: *Self) ?*T {
52 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {
50 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
5351 return &self.data;
5452 } else {
5553 return null;
......@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {
6260 /// It's not required to call start() before resolve() but it can be useful since
6361 /// this method is thread-safe.
6462 pub async fn start(self: *Self) ?*T {
65 const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;
63 const state = @cmpxchgStrong(u8, &self.available, 0, 1, .SeqCst, .SeqCst) orelse return null;
6664 switch (state) {
6765 1 => {
68 const held = await (async self.lock.acquire() catch unreachable);
66 const held = self.lock.acquire();
6967 held.release();
7068 return &self.data;
7169 },
......@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {
7775 /// Make the data become available. May be called only once.
7876 /// Before calling this, modify the `data` property.
7977 pub fn resolve(self: *Self) void {
80 const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);
78 const prev = @atomicRmw(u8, &self.available, .Xchg, 2, .SeqCst);
8179 assert(prev == 0 or prev == 1); // resolve() called twice
8280 Lock.Held.release(Lock.Held{ .lock = &self.lock });
8381 }
......@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {
8684
8785test "std.event.Future" {
8886 // https://github.com/ziglang/zig/issues/1908
89 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
87 if (builtin.single_threaded) return error.SkipZigTest;
9088
9189 const allocator = std.heap.direct_allocator;
9290
......@@ -94,38 +92,33 @@ test "std.event.Future" {
9492 try loop.initMultiThreaded(allocator);
9593 defer loop.deinit();
9694
97 const handle = try async<allocator> testFuture(&loop);
98 defer cancel handle;
95 const handle = async testFuture(&loop);
9996
10097 loop.run();
10198}
10299
103100async fn testFuture(loop: *Loop) void {
104 suspend {
105 resume @handle();
106 }
107101 var future = Future(i32).init(loop);
108102
109 const a = async waitOnFuture(&future) catch @panic("memory");
110 const b = async waitOnFuture(&future) catch @panic("memory");
111 const c = async resolveFuture(&future) catch @panic("memory");
103 var a = async waitOnFuture(&future);
104 var b = async waitOnFuture(&future);
105 var c = async resolveFuture(&future);
112106
113 const result = (await a) + (await b);
114 cancel c;
107 // TODO make this work:
108 //const result = (await a) + (await b);
109 const a_result = await a;
110 const b_result = await b;
111 const result = a_result + b_result;
112
113 await c;
115114 testing.expect(result == 12);
116115}
117116
118117async fn waitOnFuture(future: *Future(i32)) i32 {
119 suspend {
120 resume @handle();
121 }
122 return (await (async future.get() catch @panic("memory"))).*;
118 return future.get().*;
123119}
124120
125121async fn resolveFuture(future: *Future(i32)) void {
126 suspend {
127 resume @handle();
128 }
129122 future.data = 6;
130123 future.resolve();
131124}
std/event/group.zig+29-67
......@@ -2,46 +2,33 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33const Lock = std.event.Lock;
44const Loop = std.event.Loop;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
75const testing = std.testing;
86
97/// ReturnType must be `void` or `E!void`
108pub fn Group(comptime ReturnType: type) type {
119 return struct {
12 coro_stack: Stack,
10 frame_stack: Stack,
1311 alloc_stack: Stack,
1412 lock: Lock,
1513
1614 const Self = @This();
1715
1816 const Error = switch (@typeInfo(ReturnType)) {
19 builtin.TypeId.ErrorUnion => |payload| payload.error_set,
17 .ErrorUnion => |payload| payload.error_set,
2018 else => void,
2119 };
22 const Stack = std.atomic.Stack(promise->ReturnType);
20 const Stack = std.atomic.Stack(anyframe->ReturnType);
2321
2422 pub fn init(loop: *Loop) Self {
2523 return Self{
26 .coro_stack = Stack.init(),
24 .frame_stack = Stack.init(),
2725 .alloc_stack = Stack.init(),
2826 .lock = Lock.init(loop),
2927 };
3028 }
3129
32 /// Cancel all the outstanding promises. Can be called even if wait was already called.
33 pub fn deinit(self: *Self) void {
34 while (self.coro_stack.pop()) |node| {
35 cancel node.data;
36 }
37 while (self.alloc_stack.pop()) |node| {
38 cancel node.data;
39 self.lock.loop.allocator.destroy(node);
40 }
41 }
42
43 /// Add a promise to the group. Thread-safe.
44 pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
30 /// Add a frame to the group. Thread-safe.
31 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) {
4532 const node = try self.lock.loop.allocator.create(Stack.Node);
4633 node.* = Stack.Node{
4734 .next = undefined,
......@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {
5138 }
5239
5340 /// Add a node to the group. Thread-safe. Cannot fail.
54 /// `node.data` should be the promise handle to add to the group.
55 /// The node's memory should be in the coroutine frame of
41 /// `node.data` should be the frame handle to add to the group.
42 /// The node's memory should be in the function frame of
5643 /// the handle that is in the node, or somewhere guaranteed to live
5744 /// at least as long.
5845 pub fn addNode(self: *Self, node: *Stack.Node) void {
59 self.coro_stack.push(node);
60 }
61
62 /// This is equivalent to an async call, but the async function is added to the group, instead
63 /// of returning a promise. func must be async and have return type ReturnType.
64 /// Thread-safe.
65 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {
66 const S = struct {
67 async fn asyncFunc(node: **Stack.Node, args2: ...) ReturnType {
68 // TODO this is a hack to make the memory following be inside the coro frame
69 suspend {
70 var my_node: Stack.Node = undefined;
71 node.* = &my_node;
72 resume @handle();
73 }
74
75 // TODO this allocation elision should be guaranteed because we await it in
76 // this coro frame
77 return await (async func(args2) catch unreachable);
78 }
79 };
80 var node: *Stack.Node = undefined;
81 const handle = try async<self.lock.loop.allocator> S.asyncFunc(&node, args);
82 node.* = Stack.Node{
83 .next = undefined,
84 .data = handle,
85 };
86 self.coro_stack.push(node);
46 self.frame_stack.push(node);
8747 }
8848
8949 /// Wait for all the calls and promises of the group to complete.
9050 /// Thread-safe.
9151 /// Safe to call any number of times.
9252 pub async fn wait(self: *Self) ReturnType {
93 // TODO catch unreachable because the allocation can be grouped with
94 // the coro frame allocation
95 const held = await (async self.lock.acquire() catch unreachable);
53 const held = self.lock.acquire();
9654 defer held.release();
9755
98 while (self.coro_stack.pop()) |node| {
56 var result: ReturnType = {};
57
58 while (self.frame_stack.pop()) |node| {
9959 if (Error == void) {
10060 await node.data;
10161 } else {
10262 (await node.data) catch |err| {
103 self.deinit();
104 return err;
63 result = err;
10564 };
10665 }
10766 }
......@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {
11271 await handle;
11372 } else {
11473 (await handle) catch |err| {
115 self.deinit();
116 return err;
74 result = err;
11775 };
11876 }
11977 }
78 return result;
12079 }
12180 };
12281}
......@@ -131,8 +90,7 @@ test "std.event.Group" {
13190 try loop.initMultiThreaded(allocator);
13291 defer loop.deinit();
13392
134 const handle = try async<allocator> testGroup(&loop);
135 defer cancel handle;
93 const handle = async testGroup(&loop);
13694
13795 loop.run();
13896}
......@@ -140,26 +98,30 @@ test "std.event.Group" {
14098async fn testGroup(loop: *Loop) void {
14199 var count: usize = 0;
142100 var group = Group(void).init(loop);
143 group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");
144 group.call(increaseByTen, &count) catch @panic("memory");
145 await (async group.wait() catch @panic("memory"));
101 var sleep_a_little_frame = async sleepALittle(&count);
102 group.add(&sleep_a_little_frame) catch @panic("memory");
103 var increase_by_ten_frame = async increaseByTen(&count);
104 group.add(&increase_by_ten_frame) catch @panic("memory");
105 group.wait();
146106 testing.expect(count == 11);
147107
148108 var another = Group(anyerror!void).init(loop);
149 another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");
150 another.call(doSomethingThatFails) catch @panic("memory");
151 testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory")));
109 var something_else_frame = async somethingElse();
110 another.add(&something_else_frame) catch @panic("memory");
111 var something_that_fails_frame = async doSomethingThatFails();
112 another.add(&something_that_fails_frame) catch @panic("memory");
113 testing.expectError(error.ItBroke, another.wait());
152114}
153115
154116async fn sleepALittle(count: *usize) void {
155117 std.time.sleep(1 * std.time.millisecond);
156 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
118 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
157119}
158120
159121async fn increaseByTen(count: *usize) void {
160122 var i: usize = 0;
161123 while (i < 10) : (i += 1) {
162 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
124 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
163125 }
164126}
165127
std/event/io.zig+9-10
......@@ -1,6 +1,5 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;
43const assert = std.debug.assert;
54const mem = std.mem;
65
......@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {
1211 /// Return the number of bytes read. It may be less than buffer.len.
1312 /// If the number of bytes read is 0, it means end of stream.
1413 /// End of stream is not an error condition.
15 readFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!usize,
14 readFn: async fn (self: *Self, buffer: []u8) Error!usize,
1615
1716 /// Return the number of bytes read. It may be less than buffer.len.
1817 /// If the number of bytes read is 0, it means end of stream.
1918 /// End of stream is not an error condition.
2019 pub async fn read(self: *Self, buffer: []u8) !usize {
21 return await (async self.readFn(self, buffer) catch unreachable);
20 return self.readFn(self, buffer);
2221 }
2322
2423 /// Return the number of bytes read. If it is less than buffer.len
......@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {
2625 pub async fn readFull(self: *Self, buffer: []u8) !usize {
2726 var index: usize = 0;
2827 while (index != buf.len) {
29 const amt_read = try await (async self.read(buf[index..]) catch unreachable);
28 const amt_read = try self.read(buf[index..]);
3029 if (amt_read == 0) return index;
3130 index += amt_read;
3231 }
......@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {
3534
3635 /// Same as `readFull` but end of stream returns `error.EndOfStream`.
3736 pub async fn readNoEof(self: *Self, buf: []u8) !void {
38 const amt_read = try await (async self.readFull(buf[index..]) catch unreachable);
37 const amt_read = try self.readFull(buf[index..]);
3938 if (amt_read < buf.len) return error.EndOfStream;
4039 }
4140
4241 pub async fn readIntLittle(self: *Self, comptime T: type) !T {
4342 var bytes: [@sizeOf(T)]u8 = undefined;
44 try await (async self.readNoEof(bytes[0..]) catch unreachable);
43 try self.readNoEof(bytes[0..]);
4544 return mem.readIntLittle(T, &bytes);
4645 }
4746
4847 pub async fn readIntBe(self: *Self, comptime T: type) !T {
4948 var bytes: [@sizeOf(T)]u8 = undefined;
50 try await (async self.readNoEof(bytes[0..]) catch unreachable);
49 try self.readNoEof(bytes[0..]);
5150 return mem.readIntBig(T, &bytes);
5251 }
5352
5453 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
5554 var bytes: [@sizeOf(T)]u8 = undefined;
56 try await (async self.readNoEof(bytes[0..]) catch unreachable);
55 try self.readNoEof(bytes[0..]);
5756 return mem.readInt(T, &bytes, endian);
5857 }
5958
......@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {
6160 // Only extern and packed structs have defined in-memory layout.
6261 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
6362 var res: [1]T = undefined;
64 try await (async self.readNoEof(@sliceToBytes(res[0..])) catch unreachable);
63 try self.readNoEof(@sliceToBytes(res[0..]));
6564 return res[0];
6665 }
6766 };
......@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {
7271 const Self = @This();
7372 pub const Error = WriteError;
7473
75 writeFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!void,
74 writeFn: async fn (self: *Self, buffer: []u8) Error!void,
7675 };
7776}
std/event/lock.zig+24-37
......@@ -3,12 +3,10 @@ const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
55const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
86const Loop = std.event.Loop;
97
108/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and
9/// Functions which are waiting for the lock are suspended, and
1210/// are resumed when the lock is released, in order.
1311/// Allows only one actor to hold the lock.
1412pub const Lock = struct {
......@@ -17,7 +15,7 @@ pub const Lock = struct {
1715 queue: Queue,
1816 queue_empty_bit: u8, // TODO make this a bool
1917
20 const Queue = std.atomic.Queue(promise);
18 const Queue = std.atomic.Queue(anyframe);
2119
2220 pub const Held = struct {
2321 lock: *Lock,
......@@ -30,19 +28,19 @@ pub const Lock = struct {
3028 }
3129
3230 // We need to release the lock.
33 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
34 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
31 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
32 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
3533
3634 // There might be a queue item. If we know the queue is empty, we can be done,
3735 // because the other actor will try to obtain the lock.
3836 // But if there's a queue item, we are the actor which must loop and attempt
3937 // to grab the lock again.
40 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
38 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
4139 return;
4240 }
4341
4442 while (true) {
45 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
43 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 1, .SeqCst);
4644 if (old_bit != 0) {
4745 // We did not obtain the lock. Great, the queue is someone else's problem.
4846 return;
......@@ -55,11 +53,11 @@ pub const Lock = struct {
5553 }
5654
5755 // Release the lock again.
58 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
59 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
56 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
57 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
6058
6159 // Find out if we can be done.
62 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {
60 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
6361 return;
6462 }
6563 }
......@@ -88,28 +86,23 @@ pub const Lock = struct {
8886 /// All calls to acquire() and release() must complete before calling deinit().
8987 pub fn deinit(self: *Lock) void {
9088 assert(self.shared_bit == 0);
91 while (self.queue.get()) |node| cancel node.data;
89 while (self.queue.get()) |node| resume node.data;
9290 }
9391
9492 pub async fn acquire(self: *Lock) Held {
95 // TODO explicitly put this memory in the coroutine frame #1194
96 suspend {
97 resume @handle();
98 }
99 var my_tick_node = Loop.NextTickNode.init(@handle());
93 var my_tick_node = Loop.NextTickNode.init(@frame());
10094
10195 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
10296 suspend {
10397 self.queue.put(&my_tick_node);
10498
105 // At this point, we are in the queue, so we might have already been resumed and this coroutine
106 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
99 // At this point, we are in the queue, so we might have already been resumed.
107100
108101 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
109102 // will attempt to grab the lock.
110 _ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
103 _ = @atomicRmw(u8, &self.queue_empty_bit, .Xchg, 0, .SeqCst);
111104
112 const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
105 const old_bit = @atomicRmw(u8, &self.shared_bit, .Xchg, 1, .SeqCst);
113106 if (old_bit == 0) {
114107 if (self.queue.get()) |node| {
115108 // Whether this node is us or someone else, we tail resume it.
......@@ -123,8 +116,7 @@ pub const Lock = struct {
123116};
124117
125118test "std.event.Lock" {
126 // TODO https://github.com/ziglang/zig/issues/2377
127 if (true) return error.SkipZigTest;
119 // TODO https://github.com/ziglang/zig/issues/1908
128120 if (builtin.single_threaded) return error.SkipZigTest;
129121
130122 const allocator = std.heap.direct_allocator;
......@@ -136,39 +128,34 @@ test "std.event.Lock" {
136128 var lock = Lock.init(&loop);
137129 defer lock.deinit();
138130
139 const handle = try async<allocator> testLock(&loop, &lock);
140 defer cancel handle;
131 _ = async testLock(&loop, &lock);
141132 loop.run();
142133
143134 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
144135}
145136
146137async fn testLock(loop: *Loop, lock: *Lock) void {
147 // TODO explicitly put next tick node memory in the coroutine frame #1194
148 suspend {
149 resume @handle();
150 }
151 const handle1 = async lockRunner(lock) catch @panic("out of memory");
138 var handle1 = async lockRunner(lock);
152139 var tick_node1 = Loop.NextTickNode{
153140 .prev = undefined,
154141 .next = undefined,
155 .data = handle1,
142 .data = &handle1,
156143 };
157144 loop.onNextTick(&tick_node1);
158145
159 const handle2 = async lockRunner(lock) catch @panic("out of memory");
146 var handle2 = async lockRunner(lock);
160147 var tick_node2 = Loop.NextTickNode{
161148 .prev = undefined,
162149 .next = undefined,
163 .data = handle2,
150 .data = &handle2,
164151 };
165152 loop.onNextTick(&tick_node2);
166153
167 const handle3 = async lockRunner(lock) catch @panic("out of memory");
154 var handle3 = async lockRunner(lock);
168155 var tick_node3 = Loop.NextTickNode{
169156 .prev = undefined,
170157 .next = undefined,
171 .data = handle3,
158 .data = &handle3,
172159 };
173160 loop.onNextTick(&tick_node3);
174161
......@@ -185,8 +172,8 @@ async fn lockRunner(lock: *Lock) void {
185172
186173 var i: usize = 0;
187174 while (i < shared_test_data.len) : (i += 1) {
188 const lock_promise = async lock.acquire() catch @panic("out of memory");
189 const handle = await lock_promise;
175 var lock_frame = async lock.acquire();
176 const handle = await lock_frame;
190177 defer handle.release();
191178
192179 shared_test_index = 0;
std/event/locked.zig+1-1
......@@ -3,7 +3,7 @@ const Lock = std.event.Lock;
33const Loop = std.event.Loop;
44
55/// Thread-safe async/await lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and
6/// Functions which are waiting for the lock are suspended, and
77/// are resumed when the lock is released, in order.
88pub fn Locked(comptime T: type) type {
99 return struct {
std/event/loop.zig+82-69
......@@ -1,5 +1,6 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
3const root = @import("root");
34const assert = std.debug.assert;
45const testing = std.testing;
56const mem = std.mem;
......@@ -13,7 +14,7 @@ const Thread = std.Thread;
1314
1415pub const Loop = struct {
1516 allocator: *mem.Allocator,
16 next_tick_queue: std.atomic.Queue(promise),
17 next_tick_queue: std.atomic.Queue(anyframe),
1718 os_data: OsData,
1819 final_resume_node: ResumeNode,
1920 pending_event_count: usize,
......@@ -24,11 +25,11 @@ pub const Loop = struct {
2425 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
2526 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,
2627
27 pub const NextTickNode = std.atomic.Queue(promise).Node;
28 pub const NextTickNode = std.atomic.Queue(anyframe).Node;
2829
2930 pub const ResumeNode = struct {
3031 id: Id,
31 handle: promise,
32 handle: anyframe,
3233 overlapped: Overlapped,
3334
3435 pub const overlapped_init = switch (builtin.os) {
......@@ -85,18 +86,43 @@ pub const Loop = struct {
8586 };
8687 };
8788
89 pub const IoMode = enum {
90 blocking,
91 evented,
92 };
93 pub const io_mode: IoMode = if (@hasDecl(root, "io_mode")) root.io_mode else IoMode.blocking;
94 var global_instance_state: Loop = undefined;
95 const default_instance: ?*Loop = switch (io_mode) {
96 .blocking => null,
97 .evented => &global_instance_state,
98 };
99 pub const instance: ?*Loop = if (@hasDecl(root, "event_loop")) root.event_loop else default_instance;
100
101 /// TODO copy elision / named return values so that the threads referencing *Loop
102 /// have the correct pointer value.
103 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
104 pub fn init(self: *Loop, allocator: *mem.Allocator) !void {
105 if (builtin.single_threaded) {
106 return self.initSingleThreaded(allocator);
107 } else {
108 return self.initMultiThreaded(allocator);
109 }
110 }
111
88112 /// After initialization, call run().
89113 /// TODO copy elision / named return values so that the threads referencing *Loop
90114 /// have the correct pointer value.
115 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
91116 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {
92117 return self.initInternal(allocator, 1);
93118 }
94119
95120 /// The allocator must be thread-safe because we use it for multiplexing
96 /// coroutines onto kernel threads.
121 /// async functions onto kernel threads.
97122 /// After initialization, call run().
98123 /// TODO copy elision / named return values so that the threads referencing *Loop
99124 /// have the correct pointer value.
125 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
100126 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
101127 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
102128 const core_count = try Thread.cpuCount();
......@@ -110,7 +136,7 @@ pub const Loop = struct {
110136 .pending_event_count = 1,
111137 .allocator = allocator,
112138 .os_data = undefined,
113 .next_tick_queue = std.atomic.Queue(promise).init(),
139 .next_tick_queue = std.atomic.Queue(anyframe).init(),
114140 .extra_threads = undefined,
115141 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
116142 .eventfd_resume_nodes = undefined,
......@@ -397,7 +423,7 @@ pub const Loop = struct {
397423 }
398424 }
399425
400 /// resume_node must live longer than the promise that it holds a reference to.
426 /// resume_node must live longer than the anyframe that it holds a reference to.
401427 /// flags must contain EPOLLET
402428 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403429 assert(flags & os.EPOLLET == os.EPOLLET);
......@@ -428,11 +454,10 @@ pub const Loop = struct {
428454 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {
429455 defer self.linuxRemoveFd(fd);
430456 suspend {
431 // TODO explicitly put this memory in the coroutine frame #1194
432457 var resume_node = ResumeNode.Basic{
433458 .base = ResumeNode{
434459 .id = ResumeNode.Id.Basic,
435 .handle = @handle(),
460 .handle = @frame(),
436461 .overlapped = ResumeNode.overlapped_init,
437462 },
438463 };
......@@ -441,14 +466,10 @@ pub const Loop = struct {
441466 }
442467
443468 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
444 // TODO #1194
445 suspend {
446 resume @handle();
447 }
448469 var resume_node = ResumeNode.Basic{
449470 .base = ResumeNode{
450471 .id = ResumeNode.Id.Basic,
451 .handle = @handle(),
472 .handle = @frame(),
452473 .overlapped = ResumeNode.overlapped_init,
453474 },
454475 .kev = undefined,
......@@ -460,7 +481,7 @@ pub const Loop = struct {
460481 return resume_node.kev;
461482 }
462483
463 /// resume_node must live longer than the promise that it holds a reference to.
484 /// resume_node must live longer than the anyframe that it holds a reference to.
464485 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465486 self.beginOneEvent();
466487 errdefer self.finishOneEvent();
......@@ -561,10 +582,10 @@ pub const Loop = struct {
561582 self.workerRun();
562583
563584 switch (builtin.os) {
564 builtin.Os.linux,
565 builtin.Os.macosx,
566 builtin.Os.freebsd,
567 builtin.Os.netbsd,
585 .linux,
586 .macosx,
587 .freebsd,
588 .netbsd,
568589 => self.os_data.fs_thread.wait(),
569590 else => {},
570591 }
......@@ -574,45 +595,38 @@ pub const Loop = struct {
574595 }
575596 }
576597
577 /// This is equivalent to an async call, except instead of beginning execution of the async function,
578 /// it immediately returns to the caller, and the async function is queued in the event loop. It still
579 /// returns a promise to be awaited.
580 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {
581 const S = struct {
582 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
583 suspend {
584 handle.* = @handle();
585 var my_tick_node = Loop.NextTickNode{
586 .prev = undefined,
587 .next = undefined,
588 .data = @handle(),
589 };
590 loop.onNextTick(&my_tick_node);
591 }
592 // TODO guaranteed allocation elision for await in same func as async
593 return await (async func(args2) catch unreachable);
594 }
595 };
596 var handle: promise->@typeOf(func).ReturnType = undefined;
597 return async<self.allocator> S.asyncFunc(self, &handle, args);
598 /// This is equivalent to function call, except it calls `startCpuBoundOperation` first.
599 pub fn call(comptime func: var, args: ...) @typeOf(func).ReturnType {
600 startCpuBoundOperation();
601 return func(args);
598602 }
599603
600 /// Awaiting a yield lets the event loop run, starting any unstarted async operations.
604 /// Yielding lets the event loop run, starting any unstarted async operations.
601605 /// Note that async operations automatically start when a function yields for any other reason,
602606 /// for example, when async I/O is performed. This function is intended to be used only when
603607 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
604608 /// is performed.
605 pub async fn yield(self: *Loop) void {
609 pub fn yield(self: *Loop) void {
606610 suspend {
607 var my_tick_node = Loop.NextTickNode{
611 var my_tick_node = NextTickNode{
608612 .prev = undefined,
609613 .next = undefined,
610 .data = @handle(),
614 .data = @frame(),
611615 };
612616 self.onNextTick(&my_tick_node);
613617 }
614618 }
615619
620 /// If the build is multi-threaded and there is an event loop, then it calls `yield`. Otherwise,
621 /// does nothing.
622 pub fn startCpuBoundOperation() void {
623 if (builtin.single_threaded) {
624 return;
625 } else if (instance) |event_loop| {
626 event_loop.yield();
627 }
628 }
629
616630 /// call finishOneEvent when done
617631 pub fn beginOneEvent(self: *Loop) void {
618632 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
......@@ -672,9 +686,9 @@ pub const Loop = struct {
672686 const handle = resume_node.handle;
673687 const resume_node_id = resume_node.id;
674688 switch (resume_node_id) {
675 ResumeNode.Id.Basic => {},
676 ResumeNode.Id.Stop => return,
677 ResumeNode.Id.EventFd => {
689 .Basic => {},
690 .Stop => return,
691 .EventFd => {
678692 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679693 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680694 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
......@@ -696,12 +710,12 @@ pub const Loop = struct {
696710 const handle = resume_node.handle;
697711 const resume_node_id = resume_node.id;
698712 switch (resume_node_id) {
699 ResumeNode.Id.Basic => {
713 .Basic => {
700714 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);
701715 basic_node.kev = ev;
702716 },
703 ResumeNode.Id.Stop => return,
704 ResumeNode.Id.EventFd => {
717 .Stop => return,
718 .EventFd => {
705719 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
706720 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
707721 self.available_eventfd_resume_nodes.push(stack_node);
......@@ -730,9 +744,9 @@ pub const Loop = struct {
730744 const handle = resume_node.handle;
731745 const resume_node_id = resume_node.id;
732746 switch (resume_node_id) {
733 ResumeNode.Id.Basic => {},
734 ResumeNode.Id.Stop => return,
735 ResumeNode.Id.EventFd => {
747 .Basic => {},
748 .Stop => return,
749 .EventFd => {
736750 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
737751 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
738752 self.available_eventfd_resume_nodes.push(stack_node);
......@@ -750,12 +764,12 @@ pub const Loop = struct {
750764 self.beginOneEvent(); // finished in posixFsRun after processing the msg
751765 self.os_data.fs_queue.put(request_node);
752766 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
767 .macosx, .freebsd, .netbsd => {
754768 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755769 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756770 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757771 },
758 builtin.Os.linux => {
772 .linux => {
759773 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760774 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761775 switch (os.linux.getErrno(rc)) {
......@@ -781,18 +795,18 @@ pub const Loop = struct {
781795 }
782796 while (self.os_data.fs_queue.get()) |node| {
783797 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {
798 .End => return,
799 .PWriteV => |*msg| {
786800 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787801 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {
802 .PReadV => |*msg| {
789803 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790804 },
791 @TagType(fs.Request.Msg).Open => |*msg| {
805 .Open => |*msg| {
792806 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793807 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {
808 .Close => |*msg| os.close(msg.fd),
809 .WriteFile => |*msg| blk: {
796810 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797811 os.O_CLOEXEC | os.O_TRUNC;
798812 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
......@@ -804,11 +818,11 @@ pub const Loop = struct {
804818 },
805819 }
806820 switch (node.data.finish) {
807 @TagType(fs.Request.Finish).TickNode => |*tick_node| self.onNextTick(tick_node),
808 @TagType(fs.Request.Finish).DeallocCloseOperation => |close_op| {
821 .TickNode => |*tick_node| self.onNextTick(tick_node),
822 .DeallocCloseOperation => |close_op| {
809823 self.allocator.destroy(close_op);
810824 },
811 @TagType(fs.Request.Finish).NoAction => {},
825 .NoAction => {},
812826 }
813827 self.finishOneEvent();
814828 }
......@@ -864,7 +878,7 @@ pub const Loop = struct {
864878
865879test "std.event.Loop - basic" {
866880 // https://github.com/ziglang/zig/issues/1908
867 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
881 if (builtin.single_threaded) return error.SkipZigTest;
868882
869883 const allocator = std.heap.direct_allocator;
870884
......@@ -877,7 +891,7 @@ test "std.event.Loop - basic" {
877891
878892test "std.event.Loop - call" {
879893 // https://github.com/ziglang/zig/issues/1908
880 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
894 if (builtin.single_threaded) return error.SkipZigTest;
881895
882896 const allocator = std.heap.direct_allocator;
883897
......@@ -886,9 +900,8 @@ test "std.event.Loop - call" {
886900 defer loop.deinit();
887901
888902 var did_it = false;
889 const handle = try loop.call(testEventLoop);
890 const handle2 = try loop.call(testEventLoop2, handle, &did_it);
891 defer cancel handle2;
903 var handle = async Loop.call(testEventLoop);
904 var handle2 = async Loop.call(testEventLoop2, &handle, &did_it);
892905
893906 loop.run();
894907
......@@ -899,7 +912,7 @@ async fn testEventLoop() i32 {
899912 return 1234;
900913}
901914
902async fn testEventLoop2(h: promise->i32, did_it: *bool) void {
915async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
903916 const value = await h;
904917 testing.expect(value == 1234);
905918 did_it.* = true;
std/event/net.zig+27-38
......@@ -9,24 +9,24 @@ const File = std.fs.File;
99const fd_t = os.fd_t;
1010
1111pub const Server = struct {
12 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
12 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
1313
1414 loop: *Loop,
1515 sockfd: ?i32,
16 accept_coro: ?promise,
16 accept_frame: ?anyframe,
1717 listen_address: std.net.Address,
1818
1919 waiting_for_emfile_node: PromiseNode,
2020 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.TailQueue(promise).Node;
22 const PromiseNode = std.TailQueue(anyframe).Node;
2323
2424 pub fn init(loop: *Loop) Server {
25 // TODO can't initialize handler coroutine here because we need well defined copy elision
25 // TODO can't initialize handler here because we need well defined copy elision
2626 return Server{
2727 .loop = loop,
2828 .sockfd = null,
29 .accept_coro = null,
29 .accept_frame = null,
3030 .handleRequestFn = undefined,
3131 .waiting_for_emfile_node = undefined,
3232 .listen_address = undefined,
......@@ -41,7 +41,7 @@ pub const Server = struct {
4141 pub fn listen(
4242 self: *Server,
4343 address: *const std.net.Address,
44 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
44 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
4545 ) !void {
4646 self.handleRequestFn = handleRequestFn;
4747
......@@ -53,10 +53,10 @@ pub const Server = struct {
5353 try os.listen(sockfd, os.SOMAXCONN);
5454 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
5555
56 self.accept_coro = try async<self.loop.allocator> Server.handler(self);
57 errdefer cancel self.accept_coro.?;
56 self.accept_frame = async Server.handler(self);
57 errdefer await self.accept_frame.?;
5858
59 self.listen_resume_node.handle = self.accept_coro.?;
59 self.listen_resume_node.handle = self.accept_frame.?;
6060 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
6161 errdefer self.loop.removeFd(sockfd);
6262 }
......@@ -71,7 +71,7 @@ pub const Server = struct {
7171 }
7272
7373 pub fn deinit(self: *Server) void {
74 if (self.accept_coro) |accept_coro| cancel accept_coro;
74 if (self.accept_frame) |accept_frame| await accept_frame;
7575 if (self.sockfd) |sockfd| os.close(sockfd);
7676 }
7777
......@@ -86,12 +86,7 @@ pub const Server = struct {
8686 continue;
8787 }
8888 var socket = File.openHandle(accepted_fd);
89 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {
90 error.OutOfMemory => {
91 socket.close();
92 continue;
93 },
94 };
89 self.handleRequestFn(self, &accepted_addr, socket);
9590 } else |err| switch (err) {
9691 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
9792 error.ConnectionAborted => continue,
......@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
124119 mem.copy(u8, sock_addr.path[0..], path);
125120 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
126121 try os.connect_async(sockfd, &sock_addr, size);
127 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
122 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
128123 try os.getsockoptError(sockfd);
129124
130125 return sockfd;
......@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize
149144 .iov_len = buffer.len,
150145 };
151146 const iovs: *const [1]os.iovec = &iov;
152 return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);
147 return readvPosix(loop, fd, iovs, 1);
153148}
154149
155150pub const WriteError = error{};
......@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr
160155 .iov_len = buffer.len,
161156 };
162157 const iovs: *const [1]os.iovec_const = &iov;
163 return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);
158 return writevPosix(loop, fd, iovs, 1);
164159}
165160
166161pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
......@@ -174,7 +169,7 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, cou
174169 os.EINVAL => unreachable,
175170 os.EFAULT => unreachable,
176171 os.EAGAIN => {
177 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);
172 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT);
178173 continue;
179174 },
180175 os.EBADF => unreachable, // always a race condition
......@@ -205,7 +200,7 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count:
205200 os.EINVAL => unreachable,
206201 os.EFAULT => unreachable,
207202 os.EAGAIN => {
208 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);
203 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
209204 continue;
210205 },
211206 os.EBADF => unreachable, // always a race condition
......@@ -232,7 +227,7 @@ pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
232227 };
233228 }
234229
235 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
230 return writevPosix(loop, fd, iovecs.ptr, data.len);
236231}
237232
238233pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
......@@ -246,7 +241,7 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
246241 };
247242 }
248243
249 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
244 return readvPosix(loop, fd, iovecs.ptr, data.len);
250245}
251246
252247pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
......@@ -256,7 +251,7 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
256251 errdefer os.close(sockfd);
257252
258253 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
259 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
254 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
260255 try os.getsockoptError(sockfd);
261256
262257 return File.openHandle(sockfd);
......@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {
275270 tcp_server: Server,
276271
277272 const Self = @This();
278 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
273 async fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
279274 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
280275 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
281276 defer socket.close();
282 // TODO guarantee elision of this allocation
283 const next_handler = async errorableHandler(self, _addr, socket) catch unreachable;
284 (await next_handler) catch |err| {
277 const next_handler = errorableHandler(self, _addr, socket) catch |err| {
285278 std.debug.panic("unable to handle connection: {}\n", err);
286279 };
287 suspend {
288 cancel @handle();
289 }
290280 }
291281 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
292282 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
......@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {
306296 defer server.tcp_server.deinit();
307297 try server.tcp_server.listen(&addr, MyServer.handler);
308298
309 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
310 defer cancel p;
299 _ = async doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
311300 loop.run();
312301}
313302
314303async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
315304 errdefer @panic("test failure");
316305
317 var socket_file = try await try async connect(loop, address);
306 var socket_file = try connect(loop, address);
318307 defer socket_file.close();
319308
320309 var buf: [512]u8 = undefined;
......@@ -340,9 +329,9 @@ pub const OutStream = struct {
340329 };
341330 }
342331
343 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
332 async fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
344333 const self = @fieldParentPtr(OutStream, "stream", out_stream);
345 return await (async write(self.loop, self.fd, bytes) catch unreachable);
334 return write(self.loop, self.fd, bytes);
346335 }
347336};
348337
......@@ -362,8 +351,8 @@ pub const InStream = struct {
362351 };
363352 }
364353
365 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
354 async fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
366355 const self = @fieldParentPtr(InStream, "stream", in_stream);
367 return await (async read(self.loop, self.fd, bytes) catch unreachable);
356 return read(self.loop, self.fd, bytes);
368357 }
369358};
std/event/rwlock.zig+46-47
......@@ -3,12 +3,10 @@ const builtin = @import("builtin");
33const assert = std.debug.assert;
44const testing = std.testing;
55const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
86const Loop = std.event.Loop;
97
108/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and
9/// Functions which are waiting for the lock are suspended, and
1210/// are resumed when the lock is released, in order.
1311/// Many readers can hold the lock at the same time; however locking for writing is exclusive.
1412/// When a read lock is held, it will not be released until the reader queue is empty.
......@@ -28,19 +26,19 @@ pub const RwLock = struct {
2826 const ReadLock = 2;
2927 };
3028
31 const Queue = std.atomic.Queue(promise);
29 const Queue = std.atomic.Queue(anyframe);
3230
3331 pub const HeldRead = struct {
3432 lock: *RwLock,
3533
3634 pub fn release(self: HeldRead) void {
3735 // If other readers still hold the lock, we're done.
38 if (@atomicRmw(usize, &self.lock.reader_lock_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst) != 1) {
36 if (@atomicRmw(usize, &self.lock.reader_lock_count, .Sub, 1, .SeqCst) != 1) {
3937 return;
4038 }
4139
42 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
43 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
40 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
41 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
4442 // Didn't unlock. Someone else's problem.
4543 return;
4644 }
......@@ -61,17 +59,17 @@ pub const RwLock = struct {
6159 }
6260
6361 // We need to release the write lock. Check if any readers are waiting to grab the lock.
64 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
62 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, .SeqCst) == 0) {
6563 // Switch to a read lock.
66 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.ReadLock, AtomicOrder.SeqCst);
64 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.ReadLock, .SeqCst);
6765 while (self.lock.reader_queue.get()) |node| {
6866 self.lock.loop.onNextTick(node);
6967 }
7068 return;
7169 }
7270
73 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
74 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);
71 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
72 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.Unlocked, .SeqCst);
7573
7674 self.lock.commonPostUnlock();
7775 }
......@@ -93,32 +91,30 @@ pub const RwLock = struct {
9391 /// All calls to acquire() and release() must complete before calling deinit().
9492 pub fn deinit(self: *RwLock) void {
9593 assert(self.shared_state == State.Unlocked);
96 while (self.writer_queue.get()) |node| cancel node.data;
97 while (self.reader_queue.get()) |node| cancel node.data;
94 while (self.writer_queue.get()) |node| resume node.data;
95 while (self.reader_queue.get()) |node| resume node.data;
9896 }
9997
10098 pub async fn acquireRead(self: *RwLock) HeldRead {
101 _ = @atomicRmw(usize, &self.reader_lock_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
99 _ = @atomicRmw(usize, &self.reader_lock_count, .Add, 1, .SeqCst);
102100
103101 suspend {
104 // TODO explicitly put this memory in the coroutine frame #1194
105102 var my_tick_node = Loop.NextTickNode{
106 .data = @handle(),
103 .data = @frame(),
107104 .prev = undefined,
108105 .next = undefined,
109106 };
110107
111108 self.reader_queue.put(&my_tick_node);
112109
113 // At this point, we are in the reader_queue, so we might have already been resumed and this coroutine
114 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
110 // At this point, we are in the reader_queue, so we might have already been resumed.
115111
116112 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
117113 // some actor will attempt to grab the lock.
118 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
114 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 0, .SeqCst);
119115
120116 // Here we don't care if we are the one to do the locking or if it was already locked for reading.
121 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |old_state| old_state == State.ReadLock else true;
117 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst)) |old_state| old_state == State.ReadLock else true;
122118 if (have_read_lock) {
123119 // Give out all the read locks.
124120 if (self.reader_queue.get()) |first_node| {
......@@ -134,24 +130,22 @@ pub const RwLock = struct {
134130
135131 pub async fn acquireWrite(self: *RwLock) HeldWrite {
136132 suspend {
137 // TODO explicitly put this memory in the coroutine frame #1194
138133 var my_tick_node = Loop.NextTickNode{
139 .data = @handle(),
134 .data = @frame(),
140135 .prev = undefined,
141136 .next = undefined,
142137 };
143138
144139 self.writer_queue.put(&my_tick_node);
145140
146 // At this point, we are in the writer_queue, so we might have already been resumed and this coroutine
147 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
141 // At this point, we are in the writer_queue, so we might have already been resumed.
148142
149143 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
150144 // some actor will attempt to grab the lock.
151 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
145 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 0, .SeqCst);
152146
153147 // Here we must be the one to acquire the write lock. It cannot already be locked.
154 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null) {
148 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) == null) {
155149 // We now have a write lock.
156150 if (self.writer_queue.get()) |node| {
157151 // Whether this node is us or someone else, we tail resume it.
......@@ -169,8 +163,8 @@ pub const RwLock = struct {
169163 // obtain the lock.
170164 // But if there's a writer_queue item or a reader_queue item,
171165 // we are the actor which must loop and attempt to grab the lock again.
172 if (@atomicLoad(u8, &self.writer_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
173 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
166 if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
167 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) != null) {
174168 // We did not obtain the lock. Great, the queues are someone else's problem.
175169 return;
176170 }
......@@ -180,13 +174,13 @@ pub const RwLock = struct {
180174 return;
181175 }
182176 // Release the lock again.
183 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
184 _ = @atomicRmw(u8, &self.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);
177 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
178 _ = @atomicRmw(u8, &self.shared_state, .Xchg, State.Unlocked, .SeqCst);
185179 continue;
186180 }
187181
188 if (@atomicLoad(u8, &self.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {
189 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
182 if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
183 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst) != null) {
190184 // We did not obtain the lock. Great, the queues are someone else's problem.
191185 return;
192186 }
......@@ -199,8 +193,8 @@ pub const RwLock = struct {
199193 return;
200194 }
201195 // Release the lock again.
202 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
203 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {
196 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
197 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
204198 // Didn't unlock. Someone else's problem.
205199 return;
206200 }
......@@ -215,6 +209,9 @@ test "std.event.RwLock" {
215209 // https://github.com/ziglang/zig/issues/2377
216210 if (true) return error.SkipZigTest;
217211
212 // https://github.com/ziglang/zig/issues/1908
213 if (builtin.single_threaded) return error.SkipZigTest;
214
218215 const allocator = std.heap.direct_allocator;
219216
220217 var loop: Loop = undefined;
......@@ -224,8 +221,7 @@ test "std.event.RwLock" {
224221 var lock = RwLock.init(&loop);
225222 defer lock.deinit();
226223
227 const handle = try async<allocator> testLock(&loop, &lock);
228 defer cancel handle;
224 const handle = testLock(&loop, &lock);
229225 loop.run();
230226
231227 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
......@@ -233,28 +229,31 @@ test "std.event.RwLock" {
233229}
234230
235231async fn testLock(loop: *Loop, lock: *RwLock) void {
236 // TODO explicitly put next tick node memory in the coroutine frame #1194
237 suspend {
238 resume @handle();
239 }
240
241232 var read_nodes: [100]Loop.NextTickNode = undefined;
242233 for (read_nodes) |*read_node| {
243 read_node.data = async readRunner(lock) catch @panic("out of memory");
234 const frame = loop.allocator.create(@Frame(readRunner)) catch @panic("memory");
235 read_node.data = frame;
236 frame.* = async readRunner(lock);
244237 loop.onNextTick(read_node);
245238 }
246239
247240 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;
248241 for (write_nodes) |*write_node| {
249 write_node.data = async writeRunner(lock) catch @panic("out of memory");
242 const frame = loop.allocator.create(@Frame(writeRunner)) catch @panic("memory");
243 write_node.data = frame;
244 frame.* = async writeRunner(lock);
250245 loop.onNextTick(write_node);
251246 }
252247
253248 for (write_nodes) |*write_node| {
254 await @ptrCast(promise->void, write_node.data);
249 const casted = @ptrCast(*const @Frame(writeRunner), write_node.data);
250 await casted;
251 loop.allocator.destroy(casted);
255252 }
256253 for (read_nodes) |*read_node| {
257 await @ptrCast(promise->void, read_node.data);
254 const casted = @ptrCast(*const @Frame(readRunner), read_node.data);
255 await casted;
256 loop.allocator.destroy(casted);
258257 }
259258}
260259
......@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {
269268 var i: usize = 0;
270269 while (i < shared_test_data.len) : (i += 1) {
271270 std.time.sleep(100 * std.time.microsecond);
272 const lock_promise = async lock.acquireWrite() catch @panic("out of memory");
271 const lock_promise = async lock.acquireWrite();
273272 const handle = await lock_promise;
274273 defer handle.release();
275274
......@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {
287286
288287 var i: usize = 0;
289288 while (i < shared_test_data.len) : (i += 1) {
290 const lock_promise = async lock.acquireRead() catch @panic("out of memory");
289 const lock_promise = async lock.acquireRead();
291290 const handle = await lock_promise;
292291 defer handle.release();
293292
std/event/rwlocked.zig+1-1
......@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;
33const Loop = std.event.Loop;
44
55/// Thread-safe async/await RW lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and
6/// Functions which are waiting for the lock are suspended, and
77/// are resumed when the lock is released, in order.
88pub fn RwLocked(comptime T: type) type {
99 return struct {
std/fmt.zig-3
......@@ -328,9 +328,6 @@ pub fn formatType(
328328 try output(context, "error.");
329329 return output(context, @errorName(value));
330330 },
331 .Promise => {
332 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
333 },
334331 .Enum => {
335332 if (comptime std.meta.trait.hasFn("format")(T)) {
336333 return value.format(fmt, options, context, Errors, output);
std/hash.zig+9
......@@ -1,6 +1,9 @@
11const adler = @import("hash/adler.zig");
22pub const Adler32 = adler.Adler32;
33
4const auto_hash = @import("hash/auto_hash.zig");
5pub const autoHash = auto_hash.autoHash;
6
47// pub for polynomials + generic crc32 construction
58pub const crc = @import("hash/crc.zig");
69pub const Crc32 = crc.Crc32;
......@@ -16,6 +19,7 @@ pub const SipHash128 = siphash.SipHash128;
1619
1720pub const murmur = @import("hash/murmur.zig");
1821pub const Murmur2_32 = murmur.Murmur2_32;
22
1923pub const Murmur2_64 = murmur.Murmur2_64;
2024pub const Murmur3_32 = murmur.Murmur3_32;
2125
......@@ -23,11 +27,16 @@ pub const cityhash = @import("hash/cityhash.zig");
2327pub const CityHash32 = cityhash.CityHash32;
2428pub const CityHash64 = cityhash.CityHash64;
2529
30const wyhash = @import("hash/wyhash.zig");
31pub const Wyhash = wyhash.Wyhash;
32
2633test "hash" {
2734 _ = @import("hash/adler.zig");
35 _ = @import("hash/auto_hash.zig");
2836 _ = @import("hash/crc.zig");
2937 _ = @import("hash/fnv.zig");
3038 _ = @import("hash/siphash.zig");
3139 _ = @import("hash/murmur.zig");
3240 _ = @import("hash/cityhash.zig");
41 _ = @import("hash/wyhash.zig");
3342}
std/hash/auto_hash.zig created+211
......@@ -0,0 +1,211 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const meta = std.meta;
5
6/// Provides generic hashing for any eligible type.
7/// Only hashes `key` itself, pointers are not followed.
8pub fn autoHash(hasher: var, key: var) void {
9 const Key = @typeOf(key);
10 switch (@typeInfo(Key)) {
11 .NoReturn,
12 .Opaque,
13 .Undefined,
14 .ArgTuple,
15 .Void,
16 .Null,
17 .BoundFn,
18 .ComptimeFloat,
19 .ComptimeInt,
20 .Type,
21 .EnumLiteral,
22 .Frame,
23 => @compileError("cannot hash this type"),
24
25 // Help the optimizer see that hashing an int is easy by inlining!
26 // TODO Check if the situation is better after #561 is resolved.
27 .Int => @inlineCall(hasher.update, std.mem.asBytes(&key)),
28
29 .Float => |info| autoHash(hasher, @bitCast(@IntType(false, info.bits), key)),
30
31 .Bool => autoHash(hasher, @boolToInt(key)),
32 .Enum => autoHash(hasher, @enumToInt(key)),
33 .ErrorSet => autoHash(hasher, @errorToInt(key)),
34 .AnyFrame, .Fn => autoHash(hasher, @ptrToInt(key)),
35
36 .Pointer => |info| switch (info.size) {
37 builtin.TypeInfo.Pointer.Size.One,
38 builtin.TypeInfo.Pointer.Size.Many,
39 builtin.TypeInfo.Pointer.Size.C,
40 => autoHash(hasher, @ptrToInt(key)),
41
42 builtin.TypeInfo.Pointer.Size.Slice => {
43 autoHash(hasher, key.ptr);
44 autoHash(hasher, key.len);
45 },
46 },
47
48 .Optional => if (key) |k| autoHash(hasher, k),
49
50 .Array => {
51 // TODO detect via a trait when Key has no padding bits to
52 // hash it as an array of bytes.
53 // Otherwise, hash every element.
54 for (key) |element| {
55 autoHash(hasher, element);
56 }
57 },
58
59 .Vector => |info| {
60 if (info.child.bit_count % 8 == 0) {
61 // If there's no unused bits in the child type, we can just hash
62 // this as an array of bytes.
63 hasher.update(mem.asBytes(&key));
64 } else {
65 // Otherwise, hash every element.
66 // TODO remove the copy to an array once field access is done.
67 const array: [info.len]info.child = key;
68 comptime var i: u32 = 0;
69 inline while (i < info.len) : (i += 1) {
70 autoHash(hasher, array[i]);
71 }
72 }
73 },
74
75 .Struct => |info| {
76 // TODO detect via a trait when Key has no padding bits to
77 // hash it as an array of bytes.
78 // Otherwise, hash every field.
79 inline for (info.fields) |field| {
80 // We reuse the hash of the previous field as the seed for the
81 // next one so that they're dependant.
82 autoHash(hasher, @field(key, field.name));
83 }
84 },
85
86 .Union => |info| blk: {
87 if (info.tag_type) |tag_type| {
88 const tag = meta.activeTag(key);
89 const s = autoHash(hasher, tag);
90 inline for (info.fields) |field| {
91 const enum_field = field.enum_field.?;
92 if (enum_field.value == @enumToInt(tag)) {
93 autoHash(hasher, @field(key, enum_field.name));
94 // TODO use a labelled break when it does not crash the compiler.
95 // break :blk;
96 return;
97 }
98 }
99 unreachable;
100 } else @compileError("cannot hash untagged union type: " ++ @typeName(Key) ++ ", provide your own hash function");
101 },
102
103 .ErrorUnion => blk: {
104 const payload = key catch |err| {
105 autoHash(hasher, err);
106 break :blk;
107 };
108 autoHash(hasher, payload);
109 },
110 }
111}
112
113const testing = std.testing;
114const Wyhash = std.hash.Wyhash;
115
116fn testAutoHash(key: var) u64 {
117 // Any hash could be used here, for testing autoHash.
118 var hasher = Wyhash.init(0);
119 autoHash(&hasher, key);
120 return hasher.final();
121}
122
123test "autoHash slice" {
124 // Allocate one array dynamically so that we're assured it is not merged
125 // with the other by the optimization passes.
126 const array1 = try std.heap.direct_allocator.create([6]u32);
127 defer std.heap.direct_allocator.destroy(array1);
128 array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };
129 const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };
130 const a = array1[0..];
131 const b = array2[0..];
132 const c = array1[0..3];
133 testing.expect(testAutoHash(a) == testAutoHash(a));
134 testing.expect(testAutoHash(a) != testAutoHash(array1));
135 testing.expect(testAutoHash(a) != testAutoHash(b));
136 testing.expect(testAutoHash(a) != testAutoHash(c));
137}
138
139test "testAutoHash optional" {
140 const a: ?u32 = 123;
141 const b: ?u32 = null;
142 testing.expectEqual(testAutoHash(a), testAutoHash(u32(123)));
143 testing.expect(testAutoHash(a) != testAutoHash(b));
144 testing.expectEqual(testAutoHash(b), 0);
145}
146
147test "testAutoHash array" {
148 const a = [_]u32{ 1, 2, 3 };
149 const h = testAutoHash(a);
150 var hasher = Wyhash.init(0);
151 autoHash(&hasher, u32(1));
152 autoHash(&hasher, u32(2));
153 autoHash(&hasher, u32(3));
154 testing.expectEqual(h, hasher.final());
155}
156
157test "testAutoHash struct" {
158 const Foo = struct {
159 a: u32 = 1,
160 b: u32 = 2,
161 c: u32 = 3,
162 };
163 const f = Foo{};
164 const h = testAutoHash(f);
165 var hasher = Wyhash.init(0);
166 autoHash(&hasher, u32(1));
167 autoHash(&hasher, u32(2));
168 autoHash(&hasher, u32(3));
169 testing.expectEqual(h, hasher.final());
170}
171
172test "testAutoHash union" {
173 const Foo = union(enum) {
174 A: u32,
175 B: f32,
176 C: u32,
177 };
178
179 const a = Foo{ .A = 18 };
180 var b = Foo{ .B = 12.34 };
181 const c = Foo{ .C = 18 };
182 testing.expect(testAutoHash(a) == testAutoHash(a));
183 testing.expect(testAutoHash(a) != testAutoHash(b));
184 testing.expect(testAutoHash(a) != testAutoHash(c));
185
186 b = Foo{ .A = 18 };
187 testing.expect(testAutoHash(a) == testAutoHash(b));
188}
189
190test "testAutoHash vector" {
191 const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 };
192 const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 };
193 const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 };
194 testing.expect(testAutoHash(a) == testAutoHash(a));
195 testing.expect(testAutoHash(a) != testAutoHash(b));
196 testing.expect(testAutoHash(a) != testAutoHash(c));
197}
198
199test "testAutoHash error union" {
200 const Errors = error{Test};
201 const Foo = struct {
202 a: u32 = 1,
203 b: u32 = 2,
204 c: u32 = 3,
205 };
206 const f = Foo{};
207 const g: Errors!Foo = Errors.Test;
208 testing.expect(testAutoHash(f) != testAutoHash(g));
209 testing.expect(testAutoHash(f) == testAutoHash(Foo{}));
210 testing.expect(testAutoHash(g) == testAutoHash(Errors.Test));
211}
std/hash/throughput_test.zig created+148
......@@ -0,0 +1,148 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const time = std.time;
4const Timer = time.Timer;
5const hash = std.hash;
6
7const KiB = 1024;
8const MiB = 1024 * KiB;
9const GiB = 1024 * MiB;
10
11var prng = std.rand.DefaultPrng.init(0);
12
13const Hash = struct {
14 ty: type,
15 name: []const u8,
16 init_u8s: ?[]const u8 = null,
17 init_u64: ?u64 = null,
18};
19
20const siphash_key = "0123456789abcdef";
21
22const hashes = [_]Hash{
23 Hash{ .ty = hash.Wyhash, .name = "wyhash", .init_u64 = 0 },
24 Hash{ .ty = hash.SipHash64(1, 3), .name = "siphash(1,3)", .init_u8s = siphash_key },
25 Hash{ .ty = hash.SipHash64(2, 4), .name = "siphash(2,4)", .init_u8s = siphash_key },
26 Hash{ .ty = hash.Fnv1a_64, .name = "fnv1a" },
27 Hash{ .ty = hash.Crc32, .name = "crc32" },
28};
29
30const Result = struct {
31 hash: u64,
32 throughput: u64,
33};
34
35pub fn benchmarkHash(comptime H: var, bytes: usize) !Result {
36 var h = blk: {
37 if (H.init_u8s) |init| {
38 break :blk H.ty.init(init);
39 }
40 if (H.init_u64) |init| {
41 break :blk H.ty.init(init);
42 }
43 break :blk H.ty.init();
44 };
45
46 var block: [8192]u8 = undefined;
47 prng.random.bytes(block[0..]);
48
49 var offset: usize = 0;
50 var timer = try Timer.start();
51 const start = timer.lap();
52 while (offset < bytes) : (offset += block.len) {
53 h.update(block[0..]);
54 }
55 const end = timer.read();
56
57 const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s;
58 const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s);
59
60 return Result{
61 .hash = h.final(),
62 .throughput = throughput,
63 };
64}
65
66fn usage() void {
67 std.debug.warn(
68 \\throughput_test [options]
69 \\
70 \\Options:
71 \\ --filter [test-name]
72 \\ --seed [int]
73 \\ --count [int]
74 \\ --help
75 \\
76 );
77}
78
79fn mode(comptime x: comptime_int) comptime_int {
80 return if (builtin.mode == builtin.Mode.Debug) x / 64 else x;
81}
82
83// TODO(#1358): Replace with builtin formatted padding when available.
84fn printPad(stdout: var, s: []const u8) !void {
85 var i: usize = 0;
86 while (i < 12 - s.len) : (i += 1) {
87 try stdout.print(" ");
88 }
89 try stdout.print("{}", s);
90}
91
92pub fn main() !void {
93 var stdout_file = try std.io.getStdOut();
94 var stdout_out_stream = stdout_file.outStream();
95 const stdout = &stdout_out_stream.stream;
96
97 var buffer: [1024]u8 = undefined;
98 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
99 const args = try std.process.argsAlloc(&fixed.allocator);
100
101 var filter: ?[]u8 = "";
102 var count: usize = mode(128 * MiB);
103
104 var i: usize = 1;
105 while (i < args.len) : (i += 1) {
106 if (std.mem.eql(u8, args[i], "--seed")) {
107 i += 1;
108 if (i == args.len) {
109 usage();
110 std.os.exit(1);
111 }
112
113 const seed = try std.fmt.parseUnsigned(u32, args[i], 10);
114 prng.seed(seed);
115 } else if (std.mem.eql(u8, args[i], "--filter")) {
116 i += 1;
117 if (i == args.len) {
118 usage();
119 std.os.exit(1);
120 }
121
122 filter = args[i];
123 } else if (std.mem.eql(u8, args[i], "--count")) {
124 i += 1;
125 if (i == args.len) {
126 usage();
127 std.os.exit(1);
128 }
129
130 const c = try std.fmt.parseUnsigned(u32, args[i], 10);
131 count = c * MiB;
132 } else if (std.mem.eql(u8, args[i], "--help")) {
133 usage();
134 return;
135 } else {
136 usage();
137 std.os.exit(1);
138 }
139 }
140
141 inline for (hashes) |H| {
142 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
143 const result = try benchmarkHash(H, count);
144 try printPad(stdout, H.name);
145 try stdout.print(": {:4} MiB/s [{:16}]\n", result.throughput / (1 * MiB), result.hash);
146 }
147 }
148}
std/hash/wyhash.zig created+135
......@@ -0,0 +1,135 @@
1const std = @import("std");
2const mem = std.mem;
3
4const primes = [_]u64{
5 0xa0761d6478bd642f,
6 0xe7037ed1a0b428db,
7 0x8ebc6af09c88c6e3,
8 0x589965cc75374cc3,
9 0x1d8e4e27c47d124f,
10};
11
12fn read_bytes(comptime bytes: u8, data: []const u8) u64 {
13 return mem.readVarInt(u64, data[0..bytes], .Little);
14}
15
16fn read_8bytes_swapped(data: []const u8) u64 {
17 return (read_bytes(4, data) << 32 | read_bytes(4, data[4..]));
18}
19
20fn mum(a: u64, b: u64) u64 {
21 var r = std.math.mulWide(u64, a, b);
22 r = (r >> 64) ^ r;
23 return @truncate(u64, r);
24}
25
26fn mix0(a: u64, b: u64, seed: u64) u64 {
27 return mum(a ^ seed ^ primes[0], b ^ seed ^ primes[1]);
28}
29
30fn mix1(a: u64, b: u64, seed: u64) u64 {
31 return mum(a ^ seed ^ primes[2], b ^ seed ^ primes[3]);
32}
33
34pub const Wyhash = struct {
35 seed: u64,
36 msg_len: usize,
37
38 pub fn init(seed: u64) Wyhash {
39 return Wyhash{
40 .seed = seed,
41 .msg_len = 0,
42 };
43 }
44
45 fn round(self: *Wyhash, b: []const u8) void {
46 std.debug.assert(b.len == 32);
47
48 self.seed = mix0(
49 read_bytes(8, b[0..]),
50 read_bytes(8, b[8..]),
51 self.seed,
52 ) ^ mix1(
53 read_bytes(8, b[16..]),
54 read_bytes(8, b[24..]),
55 self.seed,
56 );
57 }
58
59 fn partial(self: *Wyhash, b: []const u8) void {
60 const rem_key = b;
61 const rem_len = b.len;
62
63 var seed = self.seed;
64 seed = switch (@intCast(u5, rem_len)) {
65 0 => seed,
66 1 => mix0(read_bytes(1, rem_key), primes[4], seed),
67 2 => mix0(read_bytes(2, rem_key), primes[4], seed),
68 3 => mix0((read_bytes(2, rem_key) << 8) | read_bytes(1, rem_key[2..]), primes[4], seed),
69 4 => mix0(read_bytes(4, rem_key), primes[4], seed),
70 5 => mix0((read_bytes(4, rem_key) << 8) | read_bytes(1, rem_key[4..]), primes[4], seed),
71 6 => mix0((read_bytes(4, rem_key) << 16) | read_bytes(2, rem_key[4..]), primes[4], seed),
72 7 => mix0((read_bytes(4, rem_key) << 24) | (read_bytes(2, rem_key[4..]) << 8) | read_bytes(1, rem_key[6..]), primes[4], seed),
73 8 => mix0(read_8bytes_swapped(rem_key), primes[4], seed),
74 9 => mix0(read_8bytes_swapped(rem_key), read_bytes(1, rem_key[8..]), seed),
75 10 => mix0(read_8bytes_swapped(rem_key), read_bytes(2, rem_key[8..]), seed),
76 11 => mix0(read_8bytes_swapped(rem_key), (read_bytes(2, rem_key[8..]) << 8) | read_bytes(1, rem_key[10..]), seed),
77 12 => mix0(read_8bytes_swapped(rem_key), read_bytes(4, rem_key[8..]), seed),
78 13 => mix0(read_8bytes_swapped(rem_key), (read_bytes(4, rem_key[8..]) << 8) | read_bytes(1, rem_key[12..]), seed),
79 14 => mix0(read_8bytes_swapped(rem_key), (read_bytes(4, rem_key[8..]) << 16) | read_bytes(2, rem_key[12..]), seed),
80 15 => mix0(read_8bytes_swapped(rem_key), (read_bytes(4, rem_key[8..]) << 24) | (read_bytes(2, rem_key[12..]) << 8) | read_bytes(1, rem_key[14..]), seed),
81 16 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed),
82 17 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_bytes(1, rem_key[16..]), primes[4], seed),
83 18 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_bytes(2, rem_key[16..]), primes[4], seed),
84 19 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1((read_bytes(2, rem_key[16..]) << 8) | read_bytes(1, rem_key[18..]), primes[4], seed),
85 20 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_bytes(4, rem_key[16..]), primes[4], seed),
86 21 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1((read_bytes(4, rem_key[16..]) << 8) | read_bytes(1, rem_key[20..]), primes[4], seed),
87 22 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1((read_bytes(4, rem_key[16..]) << 16) | read_bytes(2, rem_key[20..]), primes[4], seed),
88 23 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1((read_bytes(4, rem_key[16..]) << 24) | (read_bytes(2, rem_key[20..]) << 8) | read_bytes(1, rem_key[22..]), primes[4], seed),
89 24 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), primes[4], seed),
90 25 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), read_bytes(1, rem_key[24..]), seed),
91 26 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), read_bytes(2, rem_key[24..]), seed),
92 27 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(2, rem_key[24..]) << 8) | read_bytes(1, rem_key[26..]), seed),
93 28 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), read_bytes(4, rem_key[24..]), seed),
94 29 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 8) | read_bytes(1, rem_key[28..]), seed),
95 30 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 16) | read_bytes(2, rem_key[28..]), seed),
96 31 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 24) | (read_bytes(2, rem_key[28..]) << 8) | read_bytes(1, rem_key[30..]), seed),
97 };
98 self.seed = seed;
99 }
100
101 pub fn update(self: *Wyhash, b: []const u8) void {
102 var off: usize = 0;
103
104 // Full middle blocks.
105 while (off + 32 <= b.len) : (off += 32) {
106 @inlineCall(self.round, b[off .. off + 32]);
107 }
108
109 self.partial(b[off..]);
110 self.msg_len += b.len;
111 }
112
113 pub fn final(self: *Wyhash) u64 {
114 return mum(self.seed ^ self.msg_len, primes[4]);
115 }
116
117 pub fn hash(seed: u64, input: []const u8) u64 {
118 var c = Wyhash.init(seed);
119 c.update(input);
120 return c.final();
121 }
122};
123
124test "test vectors" {
125 const expectEqual = std.testing.expectEqual;
126 const hash = Wyhash.hash;
127
128 expectEqual(hash(0, ""), 0x0);
129 expectEqual(hash(1, "a"), 0xbed235177f41d328);
130 expectEqual(hash(2, "abc"), 0xbe348debe59b27c3);
131 expectEqual(hash(3, "message digest"), 0x37320f657213a290);
132 expectEqual(hash(4, "abcdefghijklmnopqrstuvwxyz"), 0xd0b270e1d8a7019c);
133 expectEqual(hash(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0x602a1894d3bbfe7f);
134 expectEqual(hash(6, "12345678901234567890123456789012345678901234567890123456789012345678901234567890"), 0x829e9c148b75970e);
135}
std/hash_map.zig+11-112
......@@ -4,6 +4,9 @@ const assert = debug.assert;
44const testing = std.testing;
55const math = std.math;
66const mem = std.mem;
7const meta = std.meta;
8const autoHash = std.hash.autoHash;
9const Wyhash = std.hash.Wyhash;
710const Allocator = mem.Allocator;
811const builtin = @import("builtin");
912
......@@ -448,15 +451,17 @@ test "iterator hash map" {
448451 try reset_map.putNoClobber(2, 22);
449452 try reset_map.putNoClobber(3, 33);
450453
454 // TODO this test depends on the hashing algorithm, because it assumes the
455 // order of the elements in the hashmap. This should not be the case.
451456 var keys = [_]i32{
457 1,
452458 3,
453459 2,
454 1,
455460 };
456461 var values = [_]i32{
462 11,
457463 33,
458464 22,
459 11,
460465 };
461466
462467 var it = reset_map.iterator();
......@@ -518,8 +523,9 @@ pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) {
518523pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
519524 return struct {
520525 fn hash(key: K) u32 {
521 comptime var rng = comptime std.rand.DefaultPrng.init(0);
522 return autoHash(key, &rng.random, u32);
526 var hasher = Wyhash.init(0);
527 autoHash(&hasher, key);
528 return @truncate(u32, hasher.final());
523529 }
524530 }.hash;
525531}
......@@ -527,114 +533,7 @@ pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
527533pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
528534 return struct {
529535 fn eql(a: K, b: K) bool {
530 return autoEql(a, b);
536 return meta.eql(a, b);
531537 }
532538 }.eql;
533539}
534
535// TODO improve these hash functions
536pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type) HashInt {
537 switch (@typeInfo(@typeOf(key))) {
538 builtin.TypeId.NoReturn,
539 builtin.TypeId.Opaque,
540 builtin.TypeId.Undefined,
541 builtin.TypeId.ArgTuple,
542 => @compileError("cannot hash this type"),
543
544 builtin.TypeId.Void,
545 builtin.TypeId.Null,
546 => return 0,
547
548 builtin.TypeId.Int => |info| {
549 const unsigned_x = @bitCast(@IntType(false, info.bits), key);
550 if (info.bits <= HashInt.bit_count) {
551 return HashInt(unsigned_x) ^ comptime rng.scalar(HashInt);
552 } else {
553 return @truncate(HashInt, unsigned_x ^ comptime rng.scalar(@typeOf(unsigned_x)));
554 }
555 },
556
557 builtin.TypeId.Float => |info| {
558 return autoHash(@bitCast(@IntType(false, info.bits), key), rng, HashInt);
559 },
560 builtin.TypeId.Bool => return autoHash(@boolToInt(key), rng, HashInt),
561 builtin.TypeId.Enum => return autoHash(@enumToInt(key), rng, HashInt),
562 builtin.TypeId.ErrorSet => return autoHash(@errorToInt(key), rng, HashInt),
563 builtin.TypeId.Promise, builtin.TypeId.Fn => return autoHash(@ptrToInt(key), rng, HashInt),
564
565 builtin.TypeId.BoundFn,
566 builtin.TypeId.ComptimeFloat,
567 builtin.TypeId.ComptimeInt,
568 builtin.TypeId.Type,
569 builtin.TypeId.EnumLiteral,
570 => return 0,
571
572 builtin.TypeId.Pointer => |info| switch (info.size) {
573 builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
574 builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
575 builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
576 builtin.TypeInfo.Pointer.Size.Slice => {
577 const interval = std.math.max(1, key.len / 256);
578 var i: usize = 0;
579 var h = comptime rng.scalar(HashInt);
580 while (i < key.len) : (i += interval) {
581 h ^= autoHash(key[i], rng, HashInt);
582 }
583 return h;
584 },
585 },
586
587 builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"),
588 builtin.TypeId.Array => @compileError("TODO auto hash for arrays"),
589 builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"),
590 builtin.TypeId.Struct => @compileError("TODO auto hash for structs"),
591 builtin.TypeId.Union => @compileError("TODO auto hash for unions"),
592 builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"),
593 }
594}
595
596pub fn autoEql(a: var, b: @typeOf(a)) bool {
597 switch (@typeInfo(@typeOf(a))) {
598 builtin.TypeId.NoReturn,
599 builtin.TypeId.Opaque,
600 builtin.TypeId.Undefined,
601 builtin.TypeId.ArgTuple,
602 => @compileError("cannot test equality of this type"),
603 builtin.TypeId.Void,
604 builtin.TypeId.Null,
605 => return true,
606 builtin.TypeId.Bool,
607 builtin.TypeId.Int,
608 builtin.TypeId.Float,
609 builtin.TypeId.ComptimeFloat,
610 builtin.TypeId.ComptimeInt,
611 builtin.TypeId.EnumLiteral,
612 builtin.TypeId.Promise,
613 builtin.TypeId.Enum,
614 builtin.TypeId.BoundFn,
615 builtin.TypeId.Fn,
616 builtin.TypeId.ErrorSet,
617 builtin.TypeId.Type,
618 => return a == b,
619
620 builtin.TypeId.Pointer => |info| switch (info.size) {
621 builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
622 builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
623 builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
624 builtin.TypeInfo.Pointer.Size.Slice => {
625 if (a.len != b.len) return false;
626 for (a) |a_item, i| {
627 if (!autoEql(a_item, b[i])) return false;
628 }
629 return true;
630 },
631 },
632
633 builtin.TypeId.Optional => @compileError("TODO auto eql for optionals"),
634 builtin.TypeId.Array => @compileError("TODO auto eql for arrays"),
635 builtin.TypeId.Struct => @compileError("TODO auto eql for structs"),
636 builtin.TypeId.Union => @compileError("TODO auto eql for unions"),
637 builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"),
638 builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"),
639 }
640}
std/http/headers.zig+11-1
......@@ -102,9 +102,19 @@ test "HeaderEntry" {
102102 testing.expectEqualSlices(u8, "x", e.value);
103103}
104104
105fn stringEql(a: []const u8, b: []const u8) bool {
106 if (a.len != b.len) return false;
107 if (a.ptr == b.ptr) return true;
108 return mem.compare(u8, a, b) == .Equal;
109}
110
111fn stringHash(s: []const u8) u32 {
112 return @truncate(u32, std.hash.Wyhash.hash(0, s));
113}
114
105115const HeaderList = std.ArrayList(HeaderEntry);
106116const HeaderIndexList = std.ArrayList(usize);
107const HeaderIndex = std.AutoHashMap([]const u8, HeaderIndexList);
117const HeaderIndex = std.HashMap([]const u8, HeaderIndexList, stringHash, stringEql);
108118
109119pub const Headers = struct {
110120 // the owned header field name is stored in the index as part of the key
std/math.zig+67-3
......@@ -242,12 +242,76 @@ pub fn floatExponentBits(comptime T: type) comptime_int {
242242 };
243243}
244244
245pub fn min(x: var, y: var) @typeOf(x + y) {
246 return if (x < y) x else y;
245/// Given two types, returns the smallest one which is capable of holding the
246/// full range of the minimum value.
247pub fn Min(comptime A: type, comptime B: type) type {
248 switch (@typeInfo(A)) {
249 .Int => |a_info| switch (@typeInfo(B)) {
250 .Int => |b_info| if (!a_info.is_signed and !b_info.is_signed) {
251 if (a_info.bits < b_info.bits) {
252 return A;
253 } else {
254 return B;
255 }
256 },
257 else => {},
258 },
259 else => {},
260 }
261 return @typeOf(A(0) + B(0));
262}
263
264/// Returns the smaller number. When one of the parameter's type's full range fits in the other,
265/// the return type is the smaller type.
266pub fn min(x: var, y: var) Min(@typeOf(x), @typeOf(y)) {
267 const Result = Min(@typeOf(x), @typeOf(y));
268 if (x < y) {
269 // TODO Zig should allow this as an implicit cast because x is immutable and in this
270 // scope it is known to fit in the return type.
271 switch (@typeInfo(Result)) {
272 .Int => return @intCast(Result, x),
273 else => return x,
274 }
275 } else {
276 // TODO Zig should allow this as an implicit cast because y is immutable and in this
277 // scope it is known to fit in the return type.
278 switch (@typeInfo(Result)) {
279 .Int => return @intCast(Result, y),
280 else => return y,
281 }
282 }
247283}
248284
249285test "math.min" {
250286 testing.expect(min(i32(-1), i32(2)) == -1);
287 {
288 var a: u16 = 999;
289 var b: u32 = 10;
290 var result = min(a, b);
291 testing.expect(@typeOf(result) == u16);
292 testing.expect(result == 10);
293 }
294 {
295 var a: f64 = 10.34;
296 var b: f32 = 999.12;
297 var result = min(a, b);
298 testing.expect(@typeOf(result) == f64);
299 testing.expect(result == 10.34);
300 }
301 {
302 var a: i8 = -127;
303 var b: i16 = -200;
304 var result = min(a, b);
305 testing.expect(@typeOf(result) == i16);
306 testing.expect(result == -200);
307 }
308 {
309 const a = 10.34;
310 var b: f32 = 999.12;
311 var result = min(a, b);
312 testing.expect(@typeOf(result) == f32);
313 testing.expect(result == 10.34);
314 }
251315}
252316
253317pub fn max(x: var, y: var) @typeOf(x + y) {
......@@ -309,7 +373,7 @@ test "math.shl" {
309373}
310374
311375/// Shifts right. Overflowed bits are truncated.
312/// A negative shift amount results in a lefft shift.
376/// A negative shift amount results in a left shift.
313377pub fn shr(comptime T: type, a: T, shift_amt: var) T {
314378 const abs_shift_amt = absCast(shift_amt);
315379 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);
std/meta.zig+1-3
......@@ -104,8 +104,7 @@ pub fn Child(comptime T: type) type {
104104 TypeId.Array => |info| info.child,
105105 TypeId.Pointer => |info| info.child,
106106 TypeId.Optional => |info| info.child,
107 TypeId.Promise => |info| if (info.child) |child| child else null,
108 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
109108 };
110109}
111110
......@@ -114,7 +113,6 @@ test "std.meta.Child" {
114113 testing.expect(Child(*u8) == u8);
115114 testing.expect(Child([]u8) == u8);
116115 testing.expect(Child(?u8) == u8);
117 testing.expect(Child(promise->u8) == u8);
118116}
119117
120118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
std/os.zig+13
......@@ -120,6 +120,19 @@ pub fn getrandom(buf: []u8) GetRandomError!void {
120120 }
121121 }
122122 }
123 if (freebsd.is_the_target) {
124 while (true) {
125 const err = std.c.getErrno(std.c.getrandom(buf.ptr, buf.len, 0));
126
127 switch (err) {
128 0 => return,
129 EINVAL => unreachable,
130 EFAULT => unreachable,
131 EINTR => continue,
132 else => return unexpectedErrno(err),
133 }
134 }
135 }
123136 if (wasi.is_the_target) {
124137 switch (wasi.random_get(buf.ptr, buf.len)) {
125138 0 => return,
std/os/bits/netbsd.zig+59
......@@ -760,3 +760,62 @@ pub const stack_t = extern struct {
760760 ss_size: isize,
761761 ss_flags: i32,
762762};
763
764pub const S_IFMT = 0o170000;
765
766pub const S_IFIFO = 0o010000;
767pub const S_IFCHR = 0o020000;
768pub const S_IFDIR = 0o040000;
769pub const S_IFBLK = 0o060000;
770pub const S_IFREG = 0o100000;
771pub const S_IFLNK = 0o120000;
772pub const S_IFSOCK = 0o140000;
773pub const S_IFWHT = 0o160000;
774
775pub const S_ISUID = 0o4000;
776pub const S_ISGID = 0o2000;
777pub const S_ISVTX = 0o1000;
778pub const S_IRWXU = 0o700;
779pub const S_IRUSR = 0o400;
780pub const S_IWUSR = 0o200;
781pub const S_IXUSR = 0o100;
782pub const S_IRWXG = 0o070;
783pub const S_IRGRP = 0o040;
784pub const S_IWGRP = 0o020;
785pub const S_IXGRP = 0o010;
786pub const S_IRWXO = 0o007;
787pub const S_IROTH = 0o004;
788pub const S_IWOTH = 0o002;
789pub const S_IXOTH = 0o001;
790
791pub fn S_ISFIFO(m: u32) bool {
792 return m & S_IFMT == S_IFIFO;
793}
794
795pub fn S_ISCHR(m: u32) bool {
796 return m & S_IFMT == S_IFCHR;
797}
798
799pub fn S_ISDIR(m: u32) bool {
800 return m & S_IFMT == S_IFDIR;
801}
802
803pub fn S_ISBLK(m: u32) bool {
804 return m & S_IFMT == S_IFBLK;
805}
806
807pub fn S_ISREG(m: u32) bool {
808 return m & S_IFMT == S_IFREG;
809}
810
811pub fn S_ISLNK(m: u32) bool {
812 return m & S_IFMT == S_IFLNK;
813}
814
815pub fn S_ISSOCK(m: u32) bool {
816 return m & S_IFMT == S_IFSOCK;
817}
818
819pub fn S_IWHT(m: u32) bool {
820 return m & S_IFMT == S_IFWHT;
821}
std/os/darwin.zig+1-1
......@@ -5,4 +5,4 @@ pub const is_the_target = switch (builtin.os) {
55 else => false,
66};
77pub usingnamespace std.c;
8pub usingnamespace @import("bits.zig");
\ No newline at end of file
8pub usingnamespace @import("bits.zig");
std/os/freebsd.zig+1-1
......@@ -2,4 +2,4 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33pub const is_the_target = builtin.os == .freebsd;
44pub usingnamespace std.c;
5pub usingnamespace @import("bits.zig");
\ No newline at end of file
5pub usingnamespace @import("bits.zig");
std/os/netbsd.zig+1
......@@ -2,3 +2,4 @@ const builtin = @import("builtin");
22const std = @import("../std.zig");
33pub const is_the_target = builtin.os == .netbsd;
44pub usingnamespace std.c;
5pub usingnamespace @import("bits.zig");
std/os/windows.zig+12-4
......@@ -138,10 +138,19 @@ pub const RtlGenRandomError = error{Unexpected};
138138/// https://github.com/rust-lang-nursery/rand/issues/111
139139/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
140140pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
141 if (advapi32.RtlGenRandom(output.ptr, output.len) == 0) {
142 switch (kernel32.GetLastError()) {
143 else => |err| return unexpectedError(err),
141 var total_read: usize = 0;
142 var buff: []u8 = output[0..];
143 const max_read_size: ULONG = maxInt(ULONG);
144
145 while (total_read < output.len) {
146 const to_read: ULONG = math.min(buff.len, max_read_size);
147
148 if (advapi32.RtlGenRandom(buff.ptr, to_read) == 0) {
149 return unexpectedError(kernel32.GetLastError());
144150 }
151
152 total_read += to_read;
153 buff = buff[to_read..];
145154 }
146155}
147156
......@@ -866,7 +875,6 @@ pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
866875 return error.Unexpected;
867876}
868877
869
870878/// Call this when you made a windows NtDll call
871879/// and you get an unexpected status.
872880pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
std/os/windows/advapi32.zig+1-1
......@@ -19,5 +19,5 @@ pub extern "advapi32" stdcallcc fn RegQueryValueExW(
1919
2020// RtlGenRandom is known as SystemFunction036 under advapi32
2121// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
22pub extern "advapi32" stdcallcc fn SystemFunction036(output: [*]u8, length: usize) BOOL;
22pub extern "advapi32" stdcallcc fn SystemFunction036(output: [*]u8, length: ULONG) BOOL;
2323pub const RtlGenRandom = SystemFunction036;
std/os/windows/bits.zig+2-2
......@@ -209,7 +209,7 @@ pub const FILE_INFORMATION_CLASS = extern enum {
209209 FileLinkInformationExBypassAccessCheck,
210210 FileStorageReserveIdInformation,
211211 FileCaseSensitiveInformationForceAccessCheck,
212 FileMaximumInformation
212 FileMaximumInformation,
213213};
214214
215215pub const OVERLAPPED = extern struct {
......@@ -731,4 +731,4 @@ pub const UNICODE_STRING = extern struct {
731731 Length: USHORT,
732732 MaximumLength: USHORT,
733733 Buffer: [*]WCHAR,
734};
\ No newline at end of file
734};
std/os/windows/ntdll.zig+8-2
......@@ -1,7 +1,13 @@
11usingnamespace @import("bits.zig");
22
33pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
4pub extern "NtDll" stdcallcc fn NtQueryInformationFile(FileHandle: HANDLE, IoStatusBlock: *IO_STATUS_BLOCK, FileInformation: *c_void, Length: ULONG, FileInformationClass: FILE_INFORMATION_CLASS,) NTSTATUS;
4pub extern "NtDll" stdcallcc fn NtQueryInformationFile(
5 FileHandle: HANDLE,
6 IoStatusBlock: *IO_STATUS_BLOCK,
7 FileInformation: *c_void,
8 Length: ULONG,
9 FileInformationClass: FILE_INFORMATION_CLASS,
10) NTSTATUS;
511pub extern "NtDll" stdcallcc fn NtCreateFile(
612 FileHandle: *HANDLE,
713 DesiredAccess: ACCESS_MASK,
......@@ -15,4 +21,4 @@ pub extern "NtDll" stdcallcc fn NtCreateFile(
1521 EaBuffer: *c_void,
1622 EaLength: ULONG,
1723) NTSTATUS;
18pub extern "NtDll" stdcallcc fn NtClose(Handle: HANDLE) NTSTATUS;
\ No newline at end of file
24pub extern "NtDll" stdcallcc fn NtClose(Handle: HANDLE) NTSTATUS;
std/os/windows/status.zig+2-2
......@@ -1,5 +1,5 @@
1/// The operation completed successfully.
1/// The operation completed successfully.
22pub const SUCCESS = 0x00000000;
33
44/// The data was too large to fit into the specified buffer.
5pub const BUFFER_OVERFLOW = 0x80000005;
\ No newline at end of file
5pub const BUFFER_OVERFLOW = 0x80000005;
std/rb.zig-1
......@@ -549,7 +549,6 @@ test "rb" {
549549 }
550550}
551551
552
553552test "inserting and looking up" {
554553 var tree: Tree = undefined;
555554 tree.init(testCompare);
std/testing.zig+26-25
......@@ -25,36 +25,37 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
2525/// The types must match exactly.
2626pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
2727 switch (@typeInfo(@typeOf(actual))) {
28 TypeId.NoReturn,
29 TypeId.BoundFn,
30 TypeId.ArgTuple,
31 TypeId.Opaque,
28 .NoReturn,
29 .BoundFn,
30 .ArgTuple,
31 .Opaque,
32 .Frame,
33 .AnyFrame,
3234 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
3335
34 TypeId.Undefined,
35 TypeId.Null,
36 TypeId.Void,
36 .Undefined,
37 .Null,
38 .Void,
3739 => return,
3840
39 TypeId.Type,
40 TypeId.Bool,
41 TypeId.Int,
42 TypeId.Float,
43 TypeId.ComptimeFloat,
44 TypeId.ComptimeInt,
45 TypeId.EnumLiteral,
46 TypeId.Enum,
47 TypeId.Fn,
48 TypeId.Promise,
49 TypeId.Vector,
50 TypeId.ErrorSet,
41 .Type,
42 .Bool,
43 .Int,
44 .Float,
45 .ComptimeFloat,
46 .ComptimeInt,
47 .EnumLiteral,
48 .Enum,
49 .Fn,
50 .Vector,
51 .ErrorSet,
5152 => {
5253 if (actual != expected) {
5354 std.debug.panic("expected {}, found {}", expected, actual);
5455 }
5556 },
5657
57 TypeId.Pointer => |pointer| {
58 .Pointer => |pointer| {
5859 switch (pointer.size) {
5960 builtin.TypeInfo.Pointer.Size.One,
6061 builtin.TypeInfo.Pointer.Size.Many,
......@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
7677 }
7778 },
7879
79 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),
80 .Array => |array| expectEqualSlices(array.child, &expected, &actual),
8081
81 TypeId.Struct => |structType| {
82 .Struct => |structType| {
8283 inline for (structType.fields) |field| {
8384 expectEqual(@field(expected, field.name), @field(actual, field.name));
8485 }
8586 },
8687
87 TypeId.Union => |union_info| {
88 .Union => |union_info| {
8889 if (union_info.tag_type == null) {
8990 @compileError("Unable to compare untagged union values");
9091 }
9192 @compileError("TODO implement testing.expectEqual for tagged unions");
9293 },
9394
94 TypeId.Optional => {
95 .Optional => {
9596 if (expected) |expected_payload| {
9697 if (actual) |actual_payload| {
9798 expectEqual(expected_payload, actual_payload);
......@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
105106 }
106107 },
107108
108 TypeId.ErrorUnion => {
109 .ErrorUnion => {
109110 if (expected) |expected_payload| {
110111 if (actual) |actual_payload| {
111112 expectEqual(expected_payload, actual_payload);
std/zig/ast.zig+10-43
......@@ -400,7 +400,7 @@ pub const Node = struct {
400400 VarType,
401401 ErrorType,
402402 FnProto,
403 PromiseType,
403 AnyFrameType,
404404
405405 // Primary expressions
406406 IntegerLiteral,
......@@ -434,7 +434,6 @@ pub const Node = struct {
434434 ErrorTag,
435435 AsmInput,
436436 AsmOutput,
437 AsyncAttribute,
438437 ParamDecl,
439438 FieldInitializer,
440439 };
......@@ -838,36 +837,6 @@ pub const Node = struct {
838837 }
839838 };
840839
841 pub const AsyncAttribute = struct {
842 base: Node,
843 async_token: TokenIndex,
844 allocator_type: ?*Node,
845 rangle_bracket: ?TokenIndex,
846
847 pub fn iterate(self: *AsyncAttribute, index: usize) ?*Node {
848 var i = index;
849
850 if (self.allocator_type) |allocator_type| {
851 if (i < 1) return allocator_type;
852 i -= 1;
853 }
854
855 return null;
856 }
857
858 pub fn firstToken(self: *const AsyncAttribute) TokenIndex {
859 return self.async_token;
860 }
861
862 pub fn lastToken(self: *const AsyncAttribute) TokenIndex {
863 if (self.rangle_bracket) |rangle_bracket| {
864 return rangle_bracket;
865 }
866
867 return self.async_token;
868 }
869 };
870
871840 pub const FnProto = struct {
872841 base: Node,
873842 doc_comments: ?*DocComment,
......@@ -879,7 +848,6 @@ pub const Node = struct {
879848 var_args_token: ?TokenIndex,
880849 extern_export_inline_token: ?TokenIndex,
881850 cc_token: ?TokenIndex,
882 async_attr: ?*AsyncAttribute,
883851 body_node: ?*Node,
884852 lib_name: ?*Node, // populated if this is an extern declaration
885853 align_expr: ?*Node, // populated if align(A) is present
......@@ -935,7 +903,6 @@ pub const Node = struct {
935903
936904 pub fn firstToken(self: *const FnProto) TokenIndex {
937905 if (self.visib_token) |visib_token| return visib_token;
938 if (self.async_attr) |async_attr| return async_attr.firstToken();
939906 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
940907 assert(self.lib_name == null);
941908 if (self.cc_token) |cc_token| return cc_token;
......@@ -952,9 +919,9 @@ pub const Node = struct {
952919 }
953920 };
954921
955 pub const PromiseType = struct {
922 pub const AnyFrameType = struct {
956923 base: Node,
957 promise_token: TokenIndex,
924 anyframe_token: TokenIndex,
958925 result: ?Result,
959926
960927 pub const Result = struct {
......@@ -962,7 +929,7 @@ pub const Node = struct {
962929 return_type: *Node,
963930 };
964931
965 pub fn iterate(self: *PromiseType, index: usize) ?*Node {
932 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
966933 var i = index;
967934
968935 if (self.result) |result| {
......@@ -973,13 +940,13 @@ pub const Node = struct {
973940 return null;
974941 }
975942
976 pub fn firstToken(self: *const PromiseType) TokenIndex {
977 return self.promise_token;
943 pub fn firstToken(self: *const AnyFrameType) TokenIndex {
944 return self.anyframe_token;
978945 }
979946
980 pub fn lastToken(self: *const PromiseType) TokenIndex {
947 pub fn lastToken(self: *const AnyFrameType) TokenIndex {
981948 if (self.result) |result| return result.return_type.lastToken();
982 return self.promise_token;
949 return self.anyframe_token;
983950 }
984951 };
985952
......@@ -1699,7 +1666,7 @@ pub const Node = struct {
16991666
17001667 pub const Call = struct {
17011668 params: ParamList,
1702 async_attr: ?*AsyncAttribute,
1669 async_token: ?TokenIndex,
17031670
17041671 pub const ParamList = SegmentedList(*Node, 2);
17051672 };
......@@ -1752,7 +1719,7 @@ pub const Node = struct {
17521719
17531720 pub fn firstToken(self: *const SuffixOp) TokenIndex {
17541721 switch (self.op) {
1755 .Call => |*call_info| if (call_info.async_attr) |async_attr| return async_attr.firstToken(),
1722 .Call => |*call_info| if (call_info.async_token) |async_token| return async_token,
17561723 else => {},
17571724 }
17581725 return self.lhs.firstToken();
std/zig/parse.zig+37-87
......@@ -277,7 +277,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
277277
278278/// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
279279fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
280 const cc = try parseFnCC(arena, it, tree);
280 const cc = parseFnCC(arena, it, tree);
281281 const fn_token = eatToken(it, .Keyword_fn) orelse {
282282 if (cc == null) return null else return error.ParseError;
283283 };
......@@ -320,7 +320,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
320320 .var_args_token = var_args_token,
321321 .extern_export_inline_token = null,
322322 .cc_token = null,
323 .async_attr = null,
324323 .body_node = null,
325324 .lib_name = null,
326325 .align_expr = align_expr,
......@@ -331,7 +330,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
331330 switch (kind) {
332331 .CC => |token| fn_proto_node.cc_token = token,
333332 .Extern => |token| fn_proto_node.extern_export_inline_token = token,
334 .Async => |node| fn_proto_node.async_attr = node,
335333 }
336334 }
337335
......@@ -814,7 +812,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
814812/// <- AsmExpr
815813/// / IfExpr
816814/// / KEYWORD_break BreakLabel? Expr?
817/// / KEYWORD_cancel Expr
818815/// / KEYWORD_comptime Expr
819816/// / KEYWORD_continue BreakLabel?
820817/// / KEYWORD_resume Expr
......@@ -839,20 +836,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
839836 return &node.base;
840837 }
841838
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
856839 if (eatToken(it, .Keyword_comptime)) |token| {
857840 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
858841 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
......@@ -1107,10 +1090,19 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
11071090}
11081091
11091092/// SuffixExpr
1110/// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
1093/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
11111094/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
11121095fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1113 if (try parseAsyncPrefix(arena, it, tree)) |async_node| {
1096 if (eatToken(it, .Keyword_async)) |async_token| {
1097 if (eatToken(it, .Keyword_fn)) |token_fn| {
1098 // HACK: If we see the keyword `fn`, then we assume that
1099 // we are parsing an async fn proto, and not a call.
1100 // We therefore put back all tokens consumed by the async
1101 // prefix...
1102 putBackToken(it, token_fn);
1103 putBackToken(it, async_token);
1104 return parsePrimaryTypeExpr(arena, it, tree);
1105 }
11141106 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
11151107 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{
11161108 .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index },
......@@ -1131,7 +1123,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
11311123 });
11321124 return null;
11331125 };
1134
11351126 const node = try arena.create(Node.SuffixOp);
11361127 node.* = Node.SuffixOp{
11371128 .base = Node{ .id = .SuffixOp },
......@@ -1139,14 +1130,13 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
11391130 .op = Node.SuffixOp.Op{
11401131 .Call = Node.SuffixOp.Op.Call{
11411132 .params = params.list,
1142 .async_attr = async_node.cast(Node.AsyncAttribute).?,
1133 .async_token = async_token,
11431134 },
11441135 },
11451136 .rtoken = params.rparen,
11461137 };
11471138 return &node.base;
11481139 }
1149
11501140 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
11511141 var res = expr;
11521142
......@@ -1168,7 +1158,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
11681158 .op = Node.SuffixOp.Op{
11691159 .Call = Node.SuffixOp.Op.Call{
11701160 .params = params.list,
1171 .async_attr = null,
1161 .async_token = null,
11721162 },
11731163 },
11741164 .rtoken = params.rparen,
......@@ -1201,7 +1191,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
12011191/// / KEYWORD_error DOT IDENTIFIER
12021192/// / KEYWORD_false
12031193/// / KEYWORD_null
1204/// / KEYWORD_promise
1194/// / KEYWORD_anyframe
12051195/// / KEYWORD_true
12061196/// / KEYWORD_undefined
12071197/// / KEYWORD_unreachable
......@@ -1256,11 +1246,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
12561246 }
12571247 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
12581248 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1259 if (eatToken(it, .Keyword_promise)) |token| {
1260 const node = try arena.create(Node.PromiseType);
1261 node.* = Node.PromiseType{
1262 .base = Node{ .id = .PromiseType },
1263 .promise_token = token,
1249 if (eatToken(it, .Keyword_anyframe)) |token| {
1250 const node = try arena.create(Node.AnyFrameType);
1251 node.* = Node.AnyFrameType{
1252 .base = Node{ .id = .AnyFrameType },
1253 .anyframe_token = token,
12641254 .result = null,
12651255 };
12661256 return &node.base;
......@@ -1668,36 +1658,18 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
16681658/// <- KEYWORD_nakedcc
16691659/// / KEYWORD_stdcallcc
16701660/// / KEYWORD_extern
1671/// / KEYWORD_async (LARROW TypeExpr RARROW)?
1672fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?FnCC {
1661/// / KEYWORD_async
1662fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?FnCC {
16731663 if (eatToken(it, .Keyword_nakedcc)) |token| return FnCC{ .CC = token };
16741664 if (eatToken(it, .Keyword_stdcallcc)) |token| return FnCC{ .CC = token };
16751665 if (eatToken(it, .Keyword_extern)) |token| return FnCC{ .Extern = token };
1676 if (eatToken(it, .Keyword_async)) |token| {
1677 const node = try arena.create(Node.AsyncAttribute);
1678 node.* = Node.AsyncAttribute{
1679 .base = Node{ .id = .AsyncAttribute },
1680 .async_token = token,
1681 .allocator_type = null,
1682 .rangle_bracket = null,
1683 };
1684 if (eatToken(it, .AngleBracketLeft)) |_| {
1685 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
1686 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
1687 });
1688 const rarrow = try expectToken(it, tree, .AngleBracketRight);
1689 node.allocator_type = type_expr;
1690 node.rangle_bracket = rarrow;
1691 }
1692 return FnCC{ .Async = node };
1693 }
1666 if (eatToken(it, .Keyword_async)) |token| return FnCC{ .CC = token };
16941667 return null;
16951668}
16961669
16971670const FnCC = union(enum) {
16981671 CC: TokenIndex,
16991672 Extern: TokenIndex,
1700 Async: *Node.AsyncAttribute,
17011673};
17021674
17031675/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
......@@ -2194,7 +2166,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
21942166
21952167/// PrefixTypeOp
21962168/// <- QUESTIONMARK
2197/// / KEYWORD_promise MINUSRARROW
2169/// / KEYWORD_anyframe MINUSRARROW
21982170/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
21992171/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
22002172fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
......@@ -2209,20 +2181,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
22092181 return &node.base;
22102182 }
22112183
2212 // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or
2184 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
22132185 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2214 // Consider making the PromiseType a member of PrefixOp and add a
2215 // PrefixOp.PromiseType variant?
2216 if (eatToken(it, .Keyword_promise)) |token| {
2186 // Consider making the AnyFrameType a member of PrefixOp and add a
2187 // PrefixOp.AnyFrameType variant?
2188 if (eatToken(it, .Keyword_anyframe)) |token| {
22172189 const arrow = eatToken(it, .Arrow) orelse {
22182190 putBackToken(it, token);
22192191 return null;
22202192 };
2221 const node = try arena.create(Node.PromiseType);
2222 node.* = Node.PromiseType{
2223 .base = Node{ .id = .PromiseType },
2224 .promise_token = token,
2225 .result = Node.PromiseType.Result{
2193 const node = try arena.create(Node.AnyFrameType);
2194 node.* = Node.AnyFrameType{
2195 .base = Node{ .id = .AnyFrameType },
2196 .anyframe_token = token,
2197 .result = Node.AnyFrameType.Result{
22262198 .arrow_token = arrow,
22272199 .return_type = undefined, // set by caller
22282200 },
......@@ -2424,28 +2396,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
24242396 return &node.base;
24252397}
24262398
2427/// AsyncPrefix <- KEYWORD_async (LARROW PrefixExpr RARROW)?
2428fn parseAsyncPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2429 const async_token = eatToken(it, .Keyword_async) orelse return null;
2430 var rangle_bracket: ?TokenIndex = null;
2431 const expr_node = if (eatToken(it, .AngleBracketLeft)) |_| blk: {
2432 const prefix_expr = try expectNode(arena, it, tree, parsePrefixExpr, AstError{
2433 .ExpectedPrefixExpr = AstError.ExpectedPrefixExpr{ .token = it.index },
2434 });
2435 rangle_bracket = try expectToken(it, tree, .AngleBracketRight);
2436 break :blk prefix_expr;
2437 } else null;
2438
2439 const node = try arena.create(Node.AsyncAttribute);
2440 node.* = Node.AsyncAttribute{
2441 .base = Node{ .id = .AsyncAttribute },
2442 .async_token = async_token,
2443 .allocator_type = expr_node,
2444 .rangle_bracket = rangle_bracket,
2445 };
2446 return &node.base;
2447}
2448
24492399/// FnCallArguments <- LPAREN ExprList RPAREN
24502400/// ExprList <- (Expr COMMA)* Expr?
24512401fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {
......@@ -2903,8 +2853,8 @@ fn parsePrefixOpExpr(
29032853 rightmost_op = rhs;
29042854 } else break;
29052855 },
2906 .PromiseType => {
2907 const prom = rightmost_op.cast(Node.PromiseType).?;
2856 .AnyFrameType => {
2857 const prom = rightmost_op.cast(Node.AnyFrameType).?;
29082858 if (try opParseFn(arena, it, tree)) |rhs| {
29092859 prom.result.?.return_type = rhs;
29102860 rightmost_op = rhs;
......@@ -2922,8 +2872,8 @@ fn parsePrefixOpExpr(
29222872 .InvalidToken = AstError.InvalidToken{ .token = it.index },
29232873 });
29242874 },
2925 .PromiseType => {
2926 const prom = rightmost_op.cast(Node.PromiseType).?;
2875 .AnyFrameType => {
2876 const prom = rightmost_op.cast(Node.AnyFrameType).?;
29272877 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
29282878 .InvalidToken = AstError.InvalidToken{ .token = it.index },
29292879 });
std/zig/parser_test.zig+20-8
......@@ -8,6 +8,18 @@ test "zig fmt: change use to usingnamespace" {
88 );
99}
1010
11test "zig fmt: async function" {
12 try testCanonical(
13 \\pub const Server = struct {
14 \\ handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
15 \\};
16 \\test "hi" {
17 \\ var ptr = @ptrCast(async fn (i32) void, other);
18 \\}
19 \\
20 );
21}
22
1123test "zig fmt: whitespace fixes" {
1224 try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n",
1325 \\test "" {
......@@ -210,7 +222,7 @@ test "zig fmt: spaces around slice operator" {
210222test "zig fmt: async call in if condition" {
211223 try testCanonical(
212224 \\comptime {
213 \\ if (async<a> b()) {
225 \\ if (async b()) {
214226 \\ a();
215227 \\ }
216228 \\}
......@@ -1118,7 +1130,7 @@ test "zig fmt: first line comment in struct initializer" {
11181130 \\pub async fn acquire(self: *Self) HeldLock {
11191131 \\ return HeldLock{
11201132 \\ // guaranteed allocation elision
1121 \\ .held = await (async self.lock.acquire() catch unreachable),
1133 \\ .held = self.lock.acquire(),
11221134 \\ .value = &self.private_data,
11231135 \\ };
11241136 \\}
......@@ -1183,7 +1195,7 @@ test "zig fmt: resume from suspend block" {
11831195 try testCanonical(
11841196 \\fn foo() void {
11851197 \\ suspend {
1186 \\ resume @handle();
1198 \\ resume @frame();
11871199 \\ }
11881200 \\}
11891201 \\
......@@ -2103,7 +2115,7 @@ test "zig fmt: inline asm" {
21032115 );
21042116}
21052117
2106test "zig fmt: coroutines" {
2118test "zig fmt: async functions" {
21072119 try testCanonical(
21082120 \\async fn simpleAsyncFn() void {
21092121 \\ const a = async a.b();
......@@ -2111,14 +2123,14 @@ test "zig fmt: coroutines" {
21112123 \\ suspend;
21122124 \\ x += 1;
21132125 \\ suspend;
2114 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;
2126 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
21152127 \\ await p;
21162128 \\}
21172129 \\
2118 \\test "coroutine suspend, resume, cancel" {
2119 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();
2130 \\test "suspend, resume, await" {
2131 \\ const p: anyframe = async testAsyncSeq();
21202132 \\ resume p;
2121 \\ cancel p;
2133 \\ await p;
21222134 \\}
21232135 \\
21242136 );
std/zig/render.zig+7-25
......@@ -284,20 +284,6 @@ fn renderExpression(
284284 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
285285 },
286286
287 ast.Node.Id.AsyncAttribute => {
288 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
289
290 if (async_attr.allocator_type) |allocator_type| {
291 try renderToken(tree, stream, async_attr.async_token, indent, start_col, Space.None); // async
292
293 try renderToken(tree, stream, tree.nextToken(async_attr.async_token), indent, start_col, Space.None); // <
294 try renderExpression(allocator, stream, tree, indent, start_col, allocator_type, Space.None); // allocator
295 return renderToken(tree, stream, tree.nextToken(allocator_type.lastToken()), indent, start_col, space); // >
296 } else {
297 return renderToken(tree, stream, async_attr.async_token, indent, start_col, space); // async
298 }
299 },
300
301287 ast.Node.Id.Suspend => {
302288 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
303289
......@@ -459,8 +445,8 @@ fn renderExpression(
459445
460446 switch (suffix_op.op) {
461447 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
462 if (call_info.async_attr) |async_attr| {
463 try renderExpression(allocator, stream, tree, indent, start_col, &async_attr.base, Space.Space);
448 if (call_info.async_token) |async_token| {
449 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
464450 }
465451
466452 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
......@@ -1121,10 +1107,6 @@ fn renderExpression(
11211107 try renderToken(tree, stream, cc_token, indent, start_col, Space.Space); // stdcallcc
11221108 }
11231109
1124 if (fn_proto.async_attr) |async_attr| {
1125 try renderExpression(allocator, stream, tree, indent, start_col, &async_attr.base, Space.Space);
1126 }
1127
11281110 const lparen = if (fn_proto.name_token) |name_token| blk: {
11291111 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
11301112 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
......@@ -1205,15 +1187,15 @@ fn renderExpression(
12051187 }
12061188 },
12071189
1208 ast.Node.Id.PromiseType => {
1209 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
1190 ast.Node.Id.AnyFrameType => {
1191 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
12101192
1211 if (promise_type.result) |result| {
1212 try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise
1193 if (anyframe_type.result) |result| {
1194 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
12131195 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
12141196 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
12151197 } else {
1216 return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise
1198 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
12171199 }
12181200 },
12191201
std/zig/tokenizer.zig+2-4
......@@ -15,12 +15,12 @@ pub const Token = struct {
1515 Keyword{ .bytes = "align", .id = Id.Keyword_align },
1616 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
1717 Keyword{ .bytes = "and", .id = Id.Keyword_and },
18 Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
1819 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
1920 Keyword{ .bytes = "async", .id = Id.Keyword_async },
2021 Keyword{ .bytes = "await", .id = Id.Keyword_await },
2122 Keyword{ .bytes = "break", .id = Id.Keyword_break },
2223 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
23 Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel },
2424 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
2525 Keyword{ .bytes = "const", .id = Id.Keyword_const },
2626 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
......@@ -42,7 +42,6 @@ pub const Token = struct {
4242 Keyword{ .bytes = "or", .id = Id.Keyword_or },
4343 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
4444 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
45 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
4645 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
4746 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
4847 Keyword{ .bytes = "return", .id = Id.Keyword_return },
......@@ -151,7 +150,6 @@ pub const Token = struct {
151150 Keyword_async,
152151 Keyword_await,
153152 Keyword_break,
154 Keyword_cancel,
155153 Keyword_catch,
156154 Keyword_comptime,
157155 Keyword_const,
......@@ -174,7 +172,7 @@ pub const Token = struct {
174172 Keyword_or,
175173 Keyword_orelse,
176174 Keyword_packed,
177 Keyword_promise,
175 Keyword_anyframe,
178176 Keyword_pub,
179177 Keyword_resume,
180178 Keyword_return,
test/compile_errors.zig+224-35
......@@ -2,6 +2,220 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "result location incompatibility mismatching handle_is_ptr (generic call)",
7 \\export fn entry() void {
8 \\ var damn = Container{
9 \\ .not_optional = getOptional(i32),
10 \\ };
11 \\}
12 \\pub fn getOptional(comptime T: type) ?T {
13 \\ return 0;
14 \\}
15 \\pub const Container = struct {
16 \\ not_optional: i32,
17 \\};
18 ,
19 "tmp.zig:3:36: error: expected type 'i32', found '?i32'",
20 );
21
22 cases.add(
23 "result location incompatibility mismatching handle_is_ptr",
24 \\export fn entry() void {
25 \\ var damn = Container{
26 \\ .not_optional = getOptional(),
27 \\ };
28 \\}
29 \\pub fn getOptional() ?i32 {
30 \\ return 0;
31 \\}
32 \\pub const Container = struct {
33 \\ not_optional: i32,
34 \\};
35 ,
36 "tmp.zig:3:36: error: expected type 'i32', found '?i32'",
37 );
38
39 cases.add(
40 "const frame cast to anyframe",
41 \\export fn a() void {
42 \\ const f = async func();
43 \\ resume f;
44 \\}
45 \\export fn b() void {
46 \\ const f = async func();
47 \\ var x: anyframe = &f;
48 \\}
49 \\fn func() void {
50 \\ suspend;
51 \\}
52 ,
53 "tmp.zig:3:12: error: expected type 'anyframe', found '*const @Frame(func)'",
54 "tmp.zig:7:24: error: expected type 'anyframe', found '*const @Frame(func)'",
55 );
56
57 cases.add(
58 "prevent bad implicit casting of anyframe types",
59 \\export fn a() void {
60 \\ var x: anyframe = undefined;
61 \\ var y: anyframe->i32 = x;
62 \\}
63 \\export fn b() void {
64 \\ var x: i32 = undefined;
65 \\ var y: anyframe->i32 = x;
66 \\}
67 \\export fn c() void {
68 \\ var x: @Frame(func) = undefined;
69 \\ var y: anyframe->i32 = &x;
70 \\}
71 \\fn func() void {}
72 ,
73 "tmp.zig:3:28: error: expected type 'anyframe->i32', found 'anyframe'",
74 "tmp.zig:7:28: error: expected type 'anyframe->i32', found 'i32'",
75 "tmp.zig:11:29: error: expected type 'anyframe->i32', found '*@Frame(func)'",
76 );
77
78 cases.add(
79 "wrong frame type used for async call",
80 \\export fn entry() void {
81 \\ var frame: @Frame(foo) = undefined;
82 \\ frame = async bar();
83 \\}
84 \\fn foo() void {
85 \\ suspend;
86 \\}
87 \\fn bar() void {
88 \\ suspend;
89 \\}
90 ,
91 "tmp.zig:3:5: error: expected type '*@Frame(bar)', found '*@Frame(foo)'",
92 );
93
94 cases.add(
95 "@Frame() of generic function",
96 \\export fn entry() void {
97 \\ var frame: @Frame(func) = undefined;
98 \\}
99 \\fn func(comptime T: type) void {
100 \\ var x: T = undefined;
101 \\}
102 ,
103 "tmp.zig:2:16: error: @Frame() of generic function",
104 );
105
106 cases.add(
107 "@frame() causes function to be async",
108 \\export fn entry() void {
109 \\ func();
110 \\}
111 \\fn func() void {
112 \\ _ = @frame();
113 \\}
114 ,
115 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
116 "tmp.zig:5:9: note: @frame() causes function to be async",
117 );
118
119 cases.add(
120 "invalid suspend in exported function",
121 \\export fn entry() void {
122 \\ var frame = async func();
123 \\ var result = await frame;
124 \\}
125 \\fn func() void {
126 \\ suspend;
127 \\}
128 ,
129 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
130 "tmp.zig:3:18: note: await is a suspend point",
131 );
132
133 cases.add(
134 "async function indirectly depends on its own frame",
135 \\export fn entry() void {
136 \\ _ = async amain();
137 \\}
138 \\async fn amain() void {
139 \\ other();
140 \\}
141 \\fn other() void {
142 \\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
143 \\}
144 ,
145 "tmp.zig:4:1: error: unable to determine async function frame of 'amain'",
146 "tmp.zig:5:10: note: analysis of function 'other' depends on the frame",
147 "tmp.zig:8:13: note: depends on the frame here",
148 );
149
150 cases.add(
151 "async function depends on its own frame",
152 \\export fn entry() void {
153 \\ _ = async amain();
154 \\}
155 \\async fn amain() void {
156 \\ var x: [@sizeOf(@Frame(amain))]u8 = undefined;
157 \\}
158 ,
159 "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet",
160 "tmp.zig:5:13: note: depends on its own frame here",
161 );
162
163 cases.add(
164 "non async function pointer passed to @asyncCall",
165 \\export fn entry() void {
166 \\ var ptr = afunc;
167 \\ var bytes: [100]u8 = undefined;
168 \\ _ = @asyncCall(&bytes, {}, ptr);
169 \\}
170 \\fn afunc() void { }
171 ,
172 "tmp.zig:4:32: error: expected async function, found 'fn() void'",
173 );
174
175 cases.add(
176 "runtime-known async function called",
177 \\export fn entry() void {
178 \\ _ = async amain();
179 \\}
180 \\fn amain() void {
181 \\ var ptr = afunc;
182 \\ _ = ptr();
183 \\}
184 \\async fn afunc() void {}
185 ,
186 "tmp.zig:6:12: error: function is not comptime-known; @asyncCall required",
187 );
188
189 cases.add(
190 "runtime-known function called with async keyword",
191 \\export fn entry() void {
192 \\ var ptr = afunc;
193 \\ _ = async ptr();
194 \\}
195 \\
196 \\async fn afunc() void { }
197 ,
198 "tmp.zig:3:15: error: function is not comptime-known; @asyncCall required",
199 );
200
201 cases.add(
202 "function with ccc indirectly calling async function",
203 \\export fn entry() void {
204 \\ foo();
205 \\}
206 \\fn foo() void {
207 \\ bar();
208 \\}
209 \\fn bar() void {
210 \\ suspend;
211 \\}
212 ,
213 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
214 "tmp.zig:2:8: note: async function call here",
215 "tmp.zig:5:8: note: async function call here",
216 "tmp.zig:8:5: note: suspends here",
217 );
218
5219 cases.add(
6220 "capture group on switch prong with incompatible payload types",
7221 \\const Union = union(enum) {
......@@ -1319,24 +1533,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
13191533 );
13201534
13211535 cases.add(
1322 "@handle() called outside of function definition",
1323 \\var handle_undef: promise = undefined;
1324 \\var handle_dummy: promise = @handle();
1536 "@frame() called outside of function definition",
1537 \\var handle_undef: anyframe = undefined;
1538 \\var handle_dummy: anyframe = @frame();
13251539 \\export fn entry() bool {
13261540 \\ return handle_undef == handle_dummy;
13271541 \\}
13281542 ,
1329 "tmp.zig:2:29: error: @handle() called outside of function definition",
1330 );
1331
1332 cases.add(
1333 "@handle() in non-async function",
1334 \\export fn entry() bool {
1335 \\ var handle_undef: promise = undefined;
1336 \\ return handle_undef == @handle();
1337 \\}
1338 ,
1339 "tmp.zig:3:28: error: @handle() in non-async function",
1543 "tmp.zig:2:30: error: @frame() called outside of function definition",
13401544 );
13411545
13421546 cases.add(
......@@ -1712,15 +1916,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17121916
17131917 cases.add(
17141918 "suspend inside suspend block",
1715 \\const std = @import("std",);
1716 \\
17171919 \\export fn entry() void {
1718 \\ var buf: [500]u8 = undefined;
1719 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
1720 \\ const p = (async<a> foo()) catch unreachable;
1721 \\ cancel p;
1920 \\ _ = async foo();
17221921 \\}
1723 \\
17241922 \\async fn foo() void {
17251923 \\ suspend {
17261924 \\ suspend {
......@@ -1728,8 +1926,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17281926 \\ }
17291927 \\}
17301928 ,
1731 "tmp.zig:12:9: error: cannot suspend inside suspend block",
1732 "tmp.zig:11:5: note: other suspend block here",
1929 "tmp.zig:6:9: error: cannot suspend inside suspend block",
1930 "tmp.zig:5:5: note: other suspend block here",
17331931 );
17341932
17351933 cases.add(
......@@ -1770,15 +1968,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17701968
17711969 cases.add(
17721970 "returning error from void async function",
1773 \\const std = @import("std",);
17741971 \\export fn entry() void {
1775 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;
1972 \\ _ = async amain();
17761973 \\}
17771974 \\async fn amain() void {
17781975 \\ return error.ShouldBeCompileError;
17791976 \\}
17801977 ,
1781 "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
1978 "tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
17821979 );
17831980
17841981 cases.add(
......@@ -3225,14 +3422,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32253422 "tmp.zig:3:17: note: value 8 cannot fit into type u3",
32263423 );
32273424
3228 cases.add(
3229 "incompatible number literals",
3230 \\const x = 2 == 2.0;
3231 \\export fn entry() usize { return @sizeOf(@typeOf(x)); }
3232 ,
3233 "tmp.zig:1:11: error: integer value 2 cannot be implicitly casted to type 'comptime_float'",
3234 );
3235
32363425 cases.add(
32373426 "missing function call param",
32383427 \\const Foo = struct {
......@@ -3315,7 +3504,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
33153504 \\
33163505 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
33173506 ,
3318 "tmp.zig:5:18: error: unable to evaluate constant expression",
3507 "tmp.zig:5:25: error: unable to evaluate constant expression",
33193508 "tmp.zig:2:12: note: called from here",
33203509 "tmp.zig:2:8: note: called from here",
33213510 );
test/runtime_safety.zig+96-5
......@@ -1,6 +1,91 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("awaiting twice",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\var frame: anyframe = undefined;
9 \\
10 \\pub fn main() void {
11 \\ _ = async amain();
12 \\ resume frame;
13 \\}
14 \\
15 \\fn amain() void {
16 \\ var f = async func();
17 \\ await f;
18 \\ await f;
19 \\}
20 \\
21 \\fn func() void {
22 \\ suspend {
23 \\ frame = @frame();
24 \\ }
25 \\}
26 );
27
28 cases.addRuntimeSafety("@asyncCall with too small a frame",
29 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
30 \\ @import("std").os.exit(126);
31 \\}
32 \\pub fn main() void {
33 \\ var bytes: [1]u8 = undefined;
34 \\ var ptr = other;
35 \\ var frame = @asyncCall(&bytes, {}, ptr);
36 \\}
37 \\async fn other() void {
38 \\ suspend;
39 \\}
40 );
41
42 cases.addRuntimeSafety("resuming a function which is awaiting a frame",
43 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
44 \\ @import("std").os.exit(126);
45 \\}
46 \\pub fn main() void {
47 \\ var frame = async first();
48 \\ resume frame;
49 \\}
50 \\fn first() void {
51 \\ var frame = async other();
52 \\ await frame;
53 \\}
54 \\fn other() void {
55 \\ suspend;
56 \\}
57 );
58
59 cases.addRuntimeSafety("resuming a function which is awaiting a call",
60 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
61 \\ @import("std").os.exit(126);
62 \\}
63 \\pub fn main() void {
64 \\ var frame = async first();
65 \\ resume frame;
66 \\}
67 \\fn first() void {
68 \\ other();
69 \\}
70 \\fn other() void {
71 \\ suspend;
72 \\}
73 );
74
75 cases.addRuntimeSafety("invalid resume of async function",
76 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
77 \\ @import("std").os.exit(126);
78 \\}
79 \\pub fn main() void {
80 \\ var p = async suspendOnce();
81 \\ resume p; //ok
82 \\ resume p; //bad
83 \\}
84 \\fn suspendOnce() void {
85 \\ suspend;
86 \\}
87 );
88
489 cases.addRuntimeSafety(".? operator on null pointer",
590 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
691 \\ @import("std").os.exit(126);
......@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
483568 \\ std.os.exit(126);
484569 \\}
485570 \\
571 \\var failing_frame: @Frame(failing) = undefined;
572 \\
486573 \\pub fn main() void {
487574 \\ const p = nonFailing();
488575 \\ resume p;
489 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;
490 \\ cancel p2;
576 \\ const p2 = async printTrace(p);
491577 \\}
492578 \\
493 \\fn nonFailing() promise->anyerror!void {
494 \\ return async<std.debug.global_allocator> failing() catch unreachable;
579 \\fn nonFailing() anyframe->anyerror!void {
580 \\ failing_frame = async failing();
581 \\ return &failing_frame;
495582 \\}
496583 \\
497584 \\async fn failing() anyerror!void {
498585 \\ suspend;
586 \\ return second();
587 \\}
588 \\
589 \\async fn second() anyerror!void {
499590 \\ return error.Fail;
500591 \\}
501592 \\
502 \\async fn printTrace(p: promise->anyerror!void) void {
593 \\async fn printTrace(p: anyframe->anyerror!void) void {
503594 \\ (await p) catch unreachable;
504595 \\}
505596 );
test/stage1/behavior.zig+6-7
......@@ -3,12 +3,13 @@ comptime {
33 _ = @import("behavior/alignof.zig");
44 _ = @import("behavior/array.zig");
55 _ = @import("behavior/asm.zig");
6 _ = @import("behavior/async_fn.zig");
67 _ = @import("behavior/atomics.zig");
8 _ = @import("behavior/await_struct.zig");
79 _ = @import("behavior/bit_shifting.zig");
810 _ = @import("behavior/bitcast.zig");
911 _ = @import("behavior/bitreverse.zig");
1012 _ = @import("behavior/bool.zig");
11 _ = @import("behavior/byteswap.zig");
1213 _ = @import("behavior/bugs/1025.zig");
1314 _ = @import("behavior/bugs/1076.zig");
1415 _ = @import("behavior/bugs/1111.zig");
......@@ -38,23 +39,23 @@ comptime {
3839 _ = @import("behavior/bugs/726.zig");
3940 _ = @import("behavior/bugs/828.zig");
4041 _ = @import("behavior/bugs/920.zig");
42 _ = @import("behavior/byteswap.zig");
4143 _ = @import("behavior/byval_arg_var.zig");
42 _ = @import("behavior/cancel.zig");
4344 _ = @import("behavior/cast.zig");
4445 _ = @import("behavior/const_slice_child.zig");
45 _ = @import("behavior/coroutine_await_struct.zig");
46 _ = @import("behavior/coroutines.zig");
4746 _ = @import("behavior/defer.zig");
4847 _ = @import("behavior/enum.zig");
4948 _ = @import("behavior/enum_with_members.zig");
5049 _ = @import("behavior/error.zig");
5150 _ = @import("behavior/eval.zig");
5251 _ = @import("behavior/field_parent_ptr.zig");
52 _ = @import("behavior/floatop.zig");
5353 _ = @import("behavior/fn.zig");
5454 _ = @import("behavior/fn_in_struct_in_comptime.zig");
5555 _ = @import("behavior/for.zig");
5656 _ = @import("behavior/generics.zig");
5757 _ = @import("behavior/hasdecl.zig");
58 _ = @import("behavior/hasfield.zig");
5859 _ = @import("behavior/if.zig");
5960 _ = @import("behavior/import.zig");
6061 _ = @import("behavior/incomplete_struct_param_tld.zig");
......@@ -63,14 +64,13 @@ comptime {
6364 _ = @import("behavior/math.zig");
6465 _ = @import("behavior/merge_error_sets.zig");
6566 _ = @import("behavior/misc.zig");
67 _ = @import("behavior/muladd.zig");
6668 _ = @import("behavior/namespace_depends_on_compile_var.zig");
6769 _ = @import("behavior/new_stack_call.zig");
6870 _ = @import("behavior/null.zig");
6971 _ = @import("behavior/optional.zig");
7072 _ = @import("behavior/pointers.zig");
7173 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
7474 _ = @import("behavior/ptrcast.zig");
7575 _ = @import("behavior/pub_enum.zig");
7676 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
......@@ -99,5 +99,4 @@ comptime {
9999 _ = @import("behavior/void.zig");
100100 _ = @import("behavior/while.zig");
101101 _ = @import("behavior/widening.zig");
102 _ = @import("behavior/hasfield.zig");
103102}
test/stage1/behavior/align.zig+62
......@@ -228,3 +228,65 @@ test "alignment of extern() void" {
228228}
229229
230230extern fn nothing() void {}
231
232test "return error union with 128-bit integer" {
233 expect(3 == try give());
234}
235fn give() anyerror!u128 {
236 return 3;
237}
238
239test "alignment of >= 128-bit integer type" {
240 expect(@alignOf(u128) == 16);
241 expect(@alignOf(u129) == 16);
242}
243
244test "alignment of struct with 128-bit field" {
245 expect(@alignOf(struct {
246 x: u128,
247 }) == 16);
248
249 comptime {
250 expect(@alignOf(struct {
251 x: u128,
252 }) == 16);
253 }
254}
255
256test "size of extern struct with 128-bit field" {
257 expect(@sizeOf(extern struct {
258 x: u128,
259 y: u8,
260 }) == 32);
261
262 comptime {
263 expect(@sizeOf(extern struct {
264 x: u128,
265 y: u8,
266 }) == 32);
267 }
268}
269
270const DefaultAligned = struct {
271 nevermind: u32,
272 badguy: i128,
273};
274
275test "read 128-bit field from default aligned struct in stack memory" {
276 var default_aligned = DefaultAligned{
277 .nevermind = 1,
278 .badguy = 12,
279 };
280 expect((@ptrToInt(&default_aligned.badguy) % 16) == 0);
281 expect(12 == default_aligned.badguy);
282}
283
284var default_aligned_global = DefaultAligned{
285 .nevermind = 1,
286 .badguy = 12,
287};
288
289test "read 128-bit field from default aligned struct in global memory" {
290 expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0);
291 expect(12 == default_aligned_global.badguy);
292}
test/stage1/behavior/async_fn.zig created+819
......@@ -0,0 +1,819 @@
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 var 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 var 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 var 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 var 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 var 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 var 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 var 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 S.doTheTest();
573}
574
575test "try in an async function with error union and non-zero-bit payload" {
576 const S = struct {
577 var frame: anyframe = undefined;
578 var ok = false;
579
580 fn doTheTest() void {
581 _ = async amain();
582 resume frame;
583 expect(ok);
584 }
585
586 fn amain() void {
587 std.testing.expectError(error.Bad, theProblem());
588 ok = true;
589 }
590
591 fn theProblem() ![]u8 {
592 frame = @frame();
593 suspend;
594 const result = try other();
595 return result;
596 }
597
598 fn other() ![]u8 {
599 return error.Bad;
600 }
601 };
602 S.doTheTest();
603}
604
605test "returning a const error from async function" {
606 const S = struct {
607 var frame: anyframe = undefined;
608 var ok = false;
609
610 fn doTheTest() void {
611 _ = async amain();
612 resume frame;
613 expect(ok);
614 }
615
616 fn amain() !void {
617 var download_frame = async fetchUrl(10, "a string");
618 const download_text = try await download_frame;
619
620 @panic("should not get here");
621 }
622
623 fn fetchUrl(unused: i32, url: []const u8) ![]u8 {
624 frame = @frame();
625 suspend;
626 ok = true;
627 return error.OutOfMemory;
628 }
629 };
630 S.doTheTest();
631}
632
633test "async/await typical usage" {
634 inline for ([_]bool{ false, true }) |b1| {
635 inline for ([_]bool{ false, true }) |b2| {
636 inline for ([_]bool{ false, true }) |b3| {
637 inline for ([_]bool{ false, true }) |b4| {
638 testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest();
639 }
640 }
641 }
642 }
643}
644
645fn testAsyncAwaitTypicalUsage(
646 comptime simulate_fail_download: bool,
647 comptime simulate_fail_file: bool,
648 comptime suspend_download: bool,
649 comptime suspend_file: bool,
650) type {
651 return struct {
652 fn doTheTest() void {
653 _ = async amainWrap();
654 if (suspend_file) {
655 resume global_file_frame;
656 }
657 if (suspend_download) {
658 resume global_download_frame;
659 }
660 }
661 fn amainWrap() void {
662 if (amain()) |_| {
663 expect(!simulate_fail_download);
664 expect(!simulate_fail_file);
665 } else |e| switch (e) {
666 error.NoResponse => expect(simulate_fail_download),
667 error.FileNotFound => expect(simulate_fail_file),
668 else => @panic("test failure"),
669 }
670 }
671
672 fn amain() !void {
673 const allocator = std.heap.direct_allocator; // TODO once we have the debug allocator, use that, so that this can detect leaks
674 var download_frame = async fetchUrl(allocator, "https://example.com/");
675 var download_awaited = false;
676 errdefer if (!download_awaited) {
677 if (await download_frame) |x| allocator.free(x) else |_| {}
678 };
679
680 var file_frame = async readFile(allocator, "something.txt");
681 var file_awaited = false;
682 errdefer if (!file_awaited) {
683 if (await file_frame) |x| allocator.free(x) else |_| {}
684 };
685
686 download_awaited = true;
687 const download_text = try await download_frame;
688 defer allocator.free(download_text);
689
690 file_awaited = true;
691 const file_text = try await file_frame;
692 defer allocator.free(file_text);
693
694 expect(std.mem.eql(u8, "expected download text", download_text));
695 expect(std.mem.eql(u8, "expected file text", file_text));
696 }
697
698 var global_download_frame: anyframe = undefined;
699 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {
700 const result = try std.mem.dupe(allocator, u8, "expected download text");
701 errdefer allocator.free(result);
702 if (suspend_download) {
703 suspend {
704 global_download_frame = @frame();
705 }
706 }
707 if (simulate_fail_download) return error.NoResponse;
708 return result;
709 }
710
711 var global_file_frame: anyframe = undefined;
712 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {
713 const result = try std.mem.dupe(allocator, u8, "expected file text");
714 errdefer allocator.free(result);
715 if (suspend_file) {
716 suspend {
717 global_file_frame = @frame();
718 }
719 }
720 if (simulate_fail_file) return error.FileNotFound;
721 return result;
722 }
723 };
724}
725
726test "alignment of local variables in async functions" {
727 const S = struct {
728 fn doTheTest() void {
729 var y: u8 = 123;
730 var x: u8 align(128) = 1;
731 expect(@ptrToInt(&x) % 128 == 0);
732 }
733 };
734 S.doTheTest();
735}
736
737test "no reason to resolve frame still works" {
738 _ = async simpleNothing();
739}
740fn simpleNothing() void {
741 var x: i32 = 1234;
742}
743
744test "async call a generic function" {
745 const S = struct {
746 fn doTheTest() void {
747 var f = async func(i32, 2);
748 const result = await f;
749 expect(result == 3);
750 }
751
752 fn func(comptime T: type, inc: T) T {
753 var x: T = 1;
754 suspend {
755 resume @frame();
756 }
757 x += inc;
758 return x;
759 }
760 };
761 _ = async S.doTheTest();
762}
763
764test "return from suspend block" {
765 const S = struct {
766 fn doTheTest() void {
767 expect(func() == 1234);
768 }
769 fn func() i32 {
770 suspend {
771 return 1234;
772 }
773 }
774 };
775 _ = async S.doTheTest();
776}
777
778test "struct parameter to async function is copied to the frame" {
779 const S = struct {
780 const Point = struct {
781 x: i32,
782 y: i32,
783 };
784
785 var frame: anyframe = undefined;
786
787 fn doTheTest() void {
788 _ = async atest();
789 resume frame;
790 }
791
792 fn atest() void {
793 var f: @Frame(foo) = undefined;
794 bar(&f);
795 clobberStack(10);
796 }
797
798 fn clobberStack(x: i32) void {
799 if (x == 0) return;
800 clobberStack(x - 1);
801 var y: i32 = x;
802 }
803
804 fn bar(f: *@Frame(foo)) void {
805 var pt = Point{ .x = 1, .y = 2 };
806 f.* = async foo(pt);
807 var result = await f;
808 expect(result == 1);
809 }
810
811 fn foo(point: Point) i32 {
812 suspend {
813 frame = @frame();
814 }
815 return point.x;
816 }
817 };
818 S.doTheTest();
819}
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 var 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 var 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/cast.zig+6-1
......@@ -508,7 +508,7 @@ test "peer type resolution: unreachable, null, slice" {
508508}
509509
510510test "peer type resolution: unreachable, error set, unreachable" {
511 const Error = error {
511 const Error = error{
512512 FileDescriptorAlreadyPresentInSet,
513513 OperationCausesCircularLoop,
514514 FileDescriptorNotRegistered,
......@@ -529,3 +529,8 @@ test "peer type resolution: unreachable, error set, unreachable" {
529529 };
530530 expect(transformed_err == error.SystemResources);
531531}
532
533test "implicit cast comptime_int to comptime_float" {
534 comptime expect(comptime_float(10) == f32(10));
535 expect(2 == 2.0);
536}
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/enum.zig+11
......@@ -982,3 +982,14 @@ test "enum literal casting to tagged union" {
982982 else => @panic("fail"),
983983 }
984984}
985
986test "enum with one member and custom tag type" {
987 const E = enum(u2) {
988 One,
989 };
990 expect(@enumToInt(E.One) == 0);
991 const E2 = enum(u2) {
992 One = 2,
993 };
994 expect(@enumToInt(E2.One) == 2);
995}
test/stage1/behavior/muladd.zig+1-1
......@@ -31,4 +31,4 @@ fn testMulAdd() void {
3131 // var c: f128 = 6.25;
3232 // expect(@mulAdd(f128, a, b, c) == 20);
3333 //}
34}
\ No newline at end of file
34}
test/stage1/behavior/type_info.zig+20-17
......@@ -116,21 +116,6 @@ fn testOptional() void {
116116 expect(null_info.Optional.child == void);
117117}
118118
119test "type info: promise info" {
120 testPromise();
121 comptime testPromise();
122}
123
124fn testPromise() void {
125 const null_promise_info = @typeInfo(promise);
126 expect(TypeId(null_promise_info) == TypeId.Promise);
127 expect(null_promise_info.Promise.child == null);
128
129 const promise_info = @typeInfo(promise->usize);
130 expect(TypeId(promise_info) == TypeId.Promise);
131 expect(promise_info.Promise.child.? == usize);
132}
133
134119test "type info: error set, error union info" {
135120 testErrorSet();
136121 comptime testErrorSet();
......@@ -192,7 +177,7 @@ fn testUnion() void {
192177 expect(TypeId(typeinfo_info) == TypeId.Union);
193178 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
194179 expect(typeinfo_info.Union.tag_type.? == TypeId);
195 expect(typeinfo_info.Union.fields.len == 25);
180 expect(typeinfo_info.Union.fields.len == 26);
196181 expect(typeinfo_info.Union.fields[4].enum_field != null);
197182 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
198183 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
......@@ -265,7 +250,6 @@ fn testFunction() void {
265250 expect(fn_info.Fn.args.len == 2);
266251 expect(fn_info.Fn.is_var_args);
267252 expect(fn_info.Fn.return_type == null);
268 expect(fn_info.Fn.async_allocator_type == null);
269253
270254 const test_instance: TestStruct = undefined;
271255 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
......@@ -296,6 +280,25 @@ fn testVector() void {
296280 expect(vec_info.Vector.child == i32);
297281}
298282
283test "type info: anyframe and anyframe->T" {
284 testAnyFrame();
285 comptime testAnyFrame();
286}
287
288fn testAnyFrame() void {
289 {
290 const anyframe_info = @typeInfo(anyframe->i32);
291 expect(TypeId(anyframe_info) == .AnyFrame);
292 expect(anyframe_info.AnyFrame.child.? == i32);
293 }
294
295 {
296 const anyframe_info = @typeInfo(anyframe);
297 expect(TypeId(anyframe_info) == .AnyFrame);
298 expect(anyframe_info.AnyFrame.child == null);
299 }
300}
301
299302test "type info: optional field unwrapping" {
300303 const Struct = struct {
301304 cdOffset: u32,
tools/process_headers.zig+3
......@@ -504,6 +504,9 @@ const Contents = struct {
504504 }
505505};
506506
507comptime {
508 @compileError("the behavior of std.AutoHashMap changed and []const u8 will be treated as a pointer. will need to update the hash maps to actually do some kind of hashing on the slices.");
509}
507510const HashToContents = std.AutoHashMap([]const u8, Contents);
508511const TargetToHash = std.HashMap(DestTarget, []const u8, DestTarget.hash, DestTarget.eql);
509512const PathTable = std.AutoHashMap([]const u8, *TargetToHash);