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()...@@ -202,11 +202,11 @@ else()
202 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Writer.cpp"202 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/Writer.cpp"
203 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/WriterUtils.cpp"203 "${CMAKE_SOURCE_DIR}/deps/lld/wasm/WriterUtils.cpp"
204 )204 )
205 add_library(embedded_lld_lib ${EMBEDDED_LLD_LIB_SOURCES})205 add_library(embedded_lld_lib STATIC ${EMBEDDED_LLD_LIB_SOURCES})
206 add_library(embedded_lld_elf ${EMBEDDED_LLD_ELF_SOURCES})206 add_library(embedded_lld_elf STATIC ${EMBEDDED_LLD_ELF_SOURCES})
207 add_library(embedded_lld_coff ${EMBEDDED_LLD_COFF_SOURCES})207 add_library(embedded_lld_coff STATIC ${EMBEDDED_LLD_COFF_SOURCES})
208 add_library(embedded_lld_mingw ${EMBEDDED_LLD_MINGW_SOURCES})208 add_library(embedded_lld_mingw STATIC ${EMBEDDED_LLD_MINGW_SOURCES})
209 add_library(embedded_lld_wasm ${EMBEDDED_LLD_WASM_SOURCES})209 add_library(embedded_lld_wasm STATIC ${EMBEDDED_LLD_WASM_SOURCES})
210 if(MSVC)210 if(MSVC)
211 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")211 set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -D_CRT_SECURE_NO_WARNINGS /w")
212 else()212 else()
...@@ -403,7 +403,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES...@@ -403,7 +403,7 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
403 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"403 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"
404 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c"404 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c"
405)405)
406add_library(embedded_softfloat ${EMBEDDED_SOFTFLOAT_SOURCES})406add_library(embedded_softfloat STATIC ${EMBEDDED_SOFTFLOAT_SOURCES})
407if(MSVC)407if(MSVC)
408 set_target_properties(embedded_softfloat PROPERTIES408 set_target_properties(embedded_softfloat PROPERTIES
409 COMPILE_FLAGS "-std=c99 /w"409 COMPILE_FLAGS "-std=c99 /w"
...@@ -429,7 +429,6 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")...@@ -429,7 +429,6 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
429set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")429set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")
430430
431set(ZIG_SOURCES431set(ZIG_SOURCES
432 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
433 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"432 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
434 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"433 "${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
435 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"434 "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
...@@ -441,6 +440,7 @@ set(ZIG_SOURCES...@@ -441,6 +440,7 @@ set(ZIG_SOURCES
441 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"440 "${CMAKE_SOURCE_DIR}/src/compiler.cpp"
442 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"441 "${CMAKE_SOURCE_DIR}/src/errmsg.cpp"
443 "${CMAKE_SOURCE_DIR}/src/error.cpp"442 "${CMAKE_SOURCE_DIR}/src/error.cpp"
443 "${CMAKE_SOURCE_DIR}/src/glibc.cpp"
444 "${CMAKE_SOURCE_DIR}/src/ir.cpp"444 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
445 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"445 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
446 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"446 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
CONTRIBUTING.md+6-6
...@@ -25,6 +25,7 @@ Here are some examples:...@@ -25,6 +25,7 @@ Here are some examples:
2525
26 * [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html)26 * [Iterative Replacement of C with Zig](http://tiehuis.github.io/blog/zig1.html)
27 * [The Right Tool for the Right Job: Redis Modules & Zig](https://www.youtube.com/watch?v=eCHM8-_poZY)27 * [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
29Zig is a brand new language, with no advertising budget. Word of mouth is the30Zig is a brand new language, with no advertising budget. Word of mouth is the
30only way people find out about the project, and the more people hear about it,31only 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....@@ -45,8 +46,8 @@ The most highly regarded argument in such a discussion is a real world use case.
4546
46The issue label47The issue label
47[Contributor Friendly](https://github.com/ziglang/zig/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributor+friendly%22)48[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/or49exists to help you find issues that are **limited in scope and/or
49knowledge of Zig internals."50knowledge of Zig internals.**
5051
51### Editing Source Code52### Editing Source Code
5253
...@@ -61,8 +62,7 @@ To test changes, do the following from the build directory:...@@ -61,8 +62,7 @@ To test changes, do the following from the build directory:
6162
621. Run `make install` (on POSIX) or631. Run `make install` (on POSIX) or
63 `msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).64 `msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
642. `bin/zig build --build-file ../build.zig test` (on POSIX) or652. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
65 `bin\zig.exe build --build-file ..\build.zig test` (on Windows).
6666
67That runs the whole test suite, which does a lot of extra testing that you67That runs the whole test suite, which does a lot of extra testing that you
68likely won't always need, and can take upwards of 2 hours. This is what the68likely 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,...@@ -79,8 +79,8 @@ Another example is choosing a different set of things to test. For example,
79not the other ones. Combining this suggestion with the previous one, you could79not the other ones. Combining this suggestion with the previous one, you could
80do this:80do this:
8181
82`bin/zig build --build-file ../build.zig test-std -Dskip-release` (on POSIX) or82`bin/zig build test-std -Dskip-release` (on POSIX) or
83`bin\zig.exe build --build-file ..\build.zig test-std -Dskip-release` (on Windows).83`bin\zig.exe build test-std -Dskip-release` (on Windows).
8484
85This will run only the standard library tests, in debug mode only, for all85This will run only the standard library tests, in debug mode only, for all
86targets (it will cross-compile the tests for non-native targets but not run86targets (it will cross-compile the tests for non-native targets but not run
README.md+2-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1![ZIG](https://ziglang.org/zig-logo.svg)1![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**,
4**optimality**, and **maintainability**.4**optimality**, and **maintainability**.
55
6## Resources6## Resources
...@@ -10,6 +10,7 @@ Zig is an open-source programming language designed for **robustness**,...@@ -10,6 +10,7 @@ Zig is an open-source programming language designed for **robustness**,
10 * [Community](https://github.com/ziglang/zig/wiki/Community)10 * [Community](https://github.com/ziglang/zig/wiki/Community)
11 * [Contributing](https://github.com/ziglang/zig/blob/master/CONTRIBUTING.md)11 * [Contributing](https://github.com/ziglang/zig/blob/master/CONTRIBUTING.md)
12 * [Frequently Asked Questions](https://github.com/ziglang/zig/wiki/FAQ)12 * [Frequently Asked Questions](https://github.com/ziglang/zig/wiki/FAQ)
13 * [Community Projects](https://github.com/ziglang/zig/wiki/Community-Projects)
1314
14## Building from Source15## Building from Source
1516
build.zig+3-1
...@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {...@@ -375,7 +375,9 @@ fn addLibUserlandStep(b: *Builder) void {
375 artifact.bundle_compiler_rt = true;375 artifact.bundle_compiler_rt = true;
376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);376 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
377 artifact.linkSystemLibrary("c");377 artifact.linkSystemLibrary("c");
378 artifact.linkSystemLibrary("ntdll");378 if (builtin.os == .windows) {
379 artifact.linkSystemLibrary("ntdll");
380 }
379 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");381 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
380 libuserland_step.dependOn(&artifact.step);382 libuserland_step.dependOn(&artifact.step);
381383
doc/docgen.zig+1-2
...@@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
750 .Keyword_async,750 .Keyword_async,
751 .Keyword_await,751 .Keyword_await,
752 .Keyword_break,752 .Keyword_break,
753 .Keyword_cancel,
754 .Keyword_catch,753 .Keyword_catch,
755 .Keyword_comptime,754 .Keyword_comptime,
756 .Keyword_const,755 .Keyword_const,
...@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -770,7 +769,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
770 .Keyword_or,769 .Keyword_or,
771 .Keyword_orelse,770 .Keyword_orelse,
772 .Keyword_packed,771 .Keyword_packed,
773 .Keyword_promise,772 .Keyword_anyframe,
774 .Keyword_pub,773 .Keyword_pub,
775 .Keyword_resume,774 .Keyword_resume,
776 .Keyword_return,775 .Keyword_return,
doc/langref.html.in+334-174
...@@ -5968,55 +5968,27 @@ test "global assembly" {...@@ -5968,55 +5968,27 @@ test "global assembly" {
5968 <p>TODO: @atomic rmw</p>5968 <p>TODO: @atomic rmw</p>
5969 <p>TODO: builtin atomic memory ordering enum</p>5969 <p>TODO: builtin atomic memory ordering enum</p>
5970 {#header_close#}5970 {#header_close#}
5971 {#header_open|Coroutines#}5971 {#header_open|Async Functions#}
5972 <p>5972 <p>
5973 A coroutine is a generalization of a function.5973 When a function is called, a frame is pushed to the stack,
5974 the function runs until it reaches a return statement, and then the frame is popped from the stack.
5975 At the callsite, the following code does not run until the function returns.
5974 </p>5976 </p>
5975 <p>5977 <p>
5976 When you call a function, it creates a stack frame,5978 An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
5977 and then the function runs until it reaches a return5979 followed by an {#syntax#}await{#endsyntax#} completion. Its frame is
5978 statement, and then the stack frame is destroyed.5980 provided explicitly by the caller, and it can be suspended and resumed any number of times.
5979 At the callsite, the next line of code does not run
5980 until the function returns.
5981 </p>5981 </p>
5982 <p>5982 <p>
5983 A coroutine is like a function, but it can be suspended5983 Zig infers that a function is {#syntax#}async{#endsyntax#} when it observes that the function contains
5984 and resumed any number of times, and then it must be5984 a <strong>suspension point</strong>. Async functions can be called the same as normal functions. A
5985 explicitly destroyed. When a coroutine suspends, it5985 function call of an async function is a suspend point.
5986 returns to the resumer.
5987 </p>
5988 {#header_open|Minimal Coroutine Example#}
5989 <p>
5990 Declare a coroutine with the {#syntax#}async{#endsyntax#} keyword.
5991 The expression in angle brackets must evaluate to a struct
5992 which has these fields:
5993 </p>
5994 <ul>
5995 <li>{#syntax#}allocFn: fn (self: *Allocator, byte_count: usize, alignment: u29) Error![]u8{#endsyntax#} - where {#syntax#}Error{#endsyntax#} can be any error set.</li>
5996 <li>{#syntax#}freeFn: fn (self: *Allocator, old_mem: []u8) void{#endsyntax#}</li>
5997 </ul>
5998 <p>
5999 You may notice that this corresponds to the {#syntax#}std.mem.Allocator{#endsyntax#} interface.
6000 This makes it convenient to integrate with existing allocators. Note, however,
6001 that the language feature does not depend on the standard library, and any struct which
6002 has these fields is allowed.
6003 </p>
6004 <p>
6005 Omitting the angle bracket expression when defining an async function makes
6006 the function generic. Zig will infer the allocator type when the async function is called.
6007 </p>
6008 <p>
6009 Call a coroutine with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
6010 is a pointer to the allocator struct that the coroutine expects.
6011 </p>
6012 <p>
6013 The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
6014 is the return type of the async function. Once a promise has been created, it must be
6015 consumed, either with {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}:
6016 </p>5986 </p>
5987 {#header_open|Suspend and Resume#}
6017 <p>5988 <p>
6018 Async functions start executing when created, so in the following example, the entire5989 At any point, a function may suspend itself. This causes control flow to
6019 async function completes before it is canceled:5990 return to the callsite (in the case of the first suspension),
5991 or resumer (in the case of subsequent suspensions).
6020 </p>5992 </p>
6021 {#code_begin|test#}5993 {#code_begin|test#}
6022const std = @import("std");5994const std = @import("std");
...@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;...@@ -6024,99 +5996,62 @@ const assert = std.debug.assert;
60245996
6025var x: i32 = 1;5997var x: i32 = 1;
60265998
6027test "create a coroutine and cancel it" {5999test "suspend with no resume" {
6028 const p = try async<std.debug.global_allocator> simpleAsyncFn();6000 var frame = async func();
6029 comptime assert(@typeOf(p) == promise->void);
6030 cancel p;
6031 assert(x == 2);6001 assert(x == 2);
6032}6002}
6033async<*std.mem.Allocator> fn simpleAsyncFn() void {
6034 x += 1;
6035}
6036 {#code_end#}
6037 {#header_close#}
6038 {#header_open|Suspend and Resume#}
6039 <p>
6040 At any point, an async function may suspend itself. This causes control flow to
6041 return to the caller or resumer. The following code demonstrates where control flow
6042 goes:
6043 </p>
6044 {#code_begin|test#}
6045const std = @import("std");
6046const assert = std.debug.assert;
6047
6048test "coroutine suspend, resume, cancel" {
6049 seq('a');
6050 const p = try async<std.debug.global_allocator> testAsyncSeq();
6051 seq('c');
6052 resume p;
6053 seq('f');
6054 cancel p;
6055 seq('g');
60566003
6057 assert(std.mem.eql(u8, points, "abcdefg"));6004fn func() void {
6058}6005 x += 1;
6059async fn testAsyncSeq() void {
6060 defer seq('e');
6061
6062 seq('b');
6063 suspend;6006 suspend;
6064 seq('d');6007 // This line is never reached because the suspend has no matching resume.
6065}6008 x += 1;
6066var points = [_]u8{0} ** "abcdefg".len;
6067var index: usize = 0;
6068
6069fn seq(c: u8) void {
6070 points[index] = c;
6071 index += 1;
6072}6009}
6073 {#code_end#}6010 {#code_end#}
6074 <p>6011 <p>
6075 When an async function suspends itself, it must be sure that it will be6012 In the same way that each allocation should have a corresponding free,
6076 resumed or canceled somehow, for example by registering its promise handle6013 Each {#syntax#}suspend{#endsyntax#} should have a corresponding {#syntax#}resume{#endsyntax#}.
6077 in an event loop. Use a suspend capture block to gain access to the6014 A <strong>suspend block</strong> allows a function to put a pointer to its own
6078 promise:6015 frame somewhere, for example into an event loop, even if that action will perform a
6016 {#syntax#}resume{#endsyntax#} operation on a different thread.
6017 {#link|@frame#} provides access to the async function frame pointer.
6079 </p>6018 </p>
6080 {#code_begin|test#}6019 {#code_begin|test#}
6081const std = @import("std");6020const std = @import("std");
6082const assert = std.debug.assert;6021const assert = std.debug.assert;
60836022
6084test "coroutine suspend with block" {6023var the_frame: anyframe = undefined;
6085 const p = try async<std.debug.global_allocator> testSuspendBlock();6024var result = false;
6086 std.debug.assert(!result);6025
6087 resume a_promise;6026test "async function suspend with block" {
6088 std.debug.assert(result);6027 _ = async testSuspendBlock();
6089 cancel p;6028 assert(!result);
6029 resume the_frame;
6030 assert(result);
6090}6031}
60916032
6092var a_promise: promise = undefined;6033fn testSuspendBlock() void {
6093var result = false;
6094async fn testSuspendBlock() void {
6095 suspend {6034 suspend {
6096 comptime assert(@typeOf(@handle()) == promise->void);6035 comptime assert(@typeOf(@frame()) == *@Frame(testSuspendBlock));
6097 a_promise = @handle();6036 the_frame = @frame();
6098 }6037 }
6099 result = true;6038 result = true;
6100}6039}
6101 {#code_end#}6040 {#code_end#}
6102 <p>6041 <p>
6103 Every suspend point in an async function represents a point at which the coroutine6042 {#syntax#}suspend{#endsyntax#} causes a function to be {#syntax#}async{#endsyntax#}.
6104 could be destroyed. If that happens, {#syntax#}defer{#endsyntax#} expressions that are in
6105 scope are run, as well as {#syntax#}errdefer{#endsyntax#} expressions.
6106 </p>
6107 <p>
6108 {#link|Await#} counts as a suspend point.
6109 </p>6043 </p>
6044
6110 {#header_open|Resuming from Suspend Blocks#}6045 {#header_open|Resuming from Suspend Blocks#}
6111 <p>6046 <p>
6112 Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered6047 Upon entering a {#syntax#}suspend{#endsyntax#} block, the async function is already considered
6113 suspended, and can be resumed. For example, if you started another kernel thread,6048 suspended, and can be resumed. For example, if you started another kernel thread,
6114 and had that thread call {#syntax#}resume{#endsyntax#} on the promise handle provided by the6049 and had that thread call {#syntax#}resume{#endsyntax#} on the frame pointer provided by the
6115 {#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend6050 {#link|@frame#}, the new thread would begin executing after the suspend
6116 block, while the old thread continued executing the suspend block.6051 block, while the old thread continued executing the suspend block.
6117 </p>6052 </p>
6118 <p>6053 <p>
6119 However, the coroutine can be directly resumed from the suspend block, in which case it6054 However, the async function can be directly resumed from the suspend block, in which case it
6120 never returns to its resumer and continues executing.6055 never returns to its resumer and continues executing.
6121 </p>6056 </p>
6122 {#code_begin|test#}6057 {#code_begin|test#}
...@@ -6124,16 +6059,13 @@ const std = @import("std");...@@ -6124,16 +6059,13 @@ const std = @import("std");
6124const assert = std.debug.assert;6059const assert = std.debug.assert;
61256060
6126test "resume from suspend" {6061test "resume from suspend" {
6127 var buf: [500]u8 = undefined;
6128 var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
6129 var my_result: i32 = 1;6062 var my_result: i32 = 1;
6130 const p = try async<a> testResumeFromSuspend(&my_result);6063 _ = async testResumeFromSuspend(&my_result);
6131 cancel p;
6132 std.debug.assert(my_result == 2);6064 std.debug.assert(my_result == 2);
6133}6065}
6134async fn testResumeFromSuspend(my_result: *i32) void {6066fn testResumeFromSuspend(my_result: *i32) void {
6135 suspend {6067 suspend {
6136 resume @handle();6068 resume @frame();
6137 }6069 }
6138 my_result.* += 1;6070 my_result.* += 1;
6139 suspend;6071 suspend;
...@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {...@@ -6141,61 +6073,88 @@ async fn testResumeFromSuspend(my_result: *i32) void {
6141}6073}
6142 {#code_end#}6074 {#code_end#}
6143 <p>6075 <p>
6144 This is guaranteed to be a tail call, and therefore will not cause a new stack frame.6076 This is guaranteed to tail call, and therefore will not cause a new stack frame.
6145 </p>6077 </p>
6146 {#header_close#}6078 {#header_close#}
6147 {#header_close#}6079 {#header_close#}
6148 {#header_open|Await#}6080
6081 {#header_open|Async and Await#}
6149 <p>6082 <p>
6150 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's6083 In the same way that every {#syntax#}suspend{#endsyntax#} has a matching
6151 {#syntax#}return{#endsyntax#} statement.6084 {#syntax#}resume{#endsyntax#}, every {#syntax#}async{#endsyntax#} has a matching {#syntax#}await{#endsyntax#}.
6152 </p>6085 </p>
6086 {#code_begin|test#}
6087const std = @import("std");
6088const assert = std.debug.assert;
6089
6090test "async and await" {
6091 // Here we have an exception where we do not match an async
6092 // with an await. The test block is not async and so cannot
6093 // have a suspend point in it.
6094 // This is well-defined behavior, and everything is OK here.
6095 // Note however that there would be no way to collect the
6096 // return value of amain, if it were something other than void.
6097 _ = async amain();
6098}
6099
6100fn amain() void {
6101 var frame = async func();
6102 comptime assert(@typeOf(frame) == @Frame(func));
6103
6104 const ptr: anyframe->void = &frame;
6105 const any_ptr: anyframe = ptr;
6106
6107 resume any_ptr;
6108 await ptr;
6109}
6110
6111fn func() void {
6112 suspend;
6113}
6114 {#code_end#}
6153 <p>6115 <p>
6154 {#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes6116 The {#syntax#}await{#endsyntax#} keyword is used to coordinate with an async function's
6155 as an operand a promise handle.6117 {#syntax#}return{#endsyntax#} statement.
6156 If the async function associated with the promise handle has already returned,
6157 then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
6158 Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
6159 promise handle with the target coroutine. It becomes the target coroutine's responsibility
6160 to have ensured that it will be resumed or destroyed. When the target coroutine reaches
6161 its return statement, it gives the return value to the awaiter, destroys itself, and then
6162 resumes the awaiter.
6163 </p>6118 </p>
6164 <p>6119 <p>
6165 A promise handle must be consumed exactly once after it is created, either by {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}.6120 {#syntax#}await{#endsyntax#} is a suspend point, and takes as an operand anything that
6121 implicitly casts to {#syntax#}anyframe->T{#endsyntax#}.
6166 </p>6122 </p>
6167 <p>6123 <p>
6168 {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},6124 There is a common misconception that {#syntax#}await{#endsyntax#} resumes the target function.
6169 a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.6125 It is the other way around: it suspends until the target function completes.
6126 In the event that the target function has already completed, {#syntax#}await{#endsyntax#}
6127 does not suspend; instead it copies the
6128 return value directly from the target function's frame.
6170 </p>6129 </p>
6171 {#code_begin|test#}6130 {#code_begin|test#}
6172const std = @import("std");6131const std = @import("std");
6173const assert = std.debug.assert;6132const assert = std.debug.assert;
61746133
6175var a_promise: promise = undefined;6134var the_frame: anyframe = undefined;
6176var final_result: i32 = 0;6135var final_result: i32 = 0;
61776136
6178test "coroutine await" {6137test "async function await" {
6179 seq('a');6138 seq('a');
6180 const p = async<std.debug.global_allocator> amain() catch unreachable;6139 _ = async amain();
6181 seq('f');6140 seq('f');
6182 resume a_promise;6141 resume the_frame;
6183 seq('i');6142 seq('i');
6184 assert(final_result == 1234);6143 assert(final_result == 1234);
6185 assert(std.mem.eql(u8, seq_points, "abcdefghi"));6144 assert(std.mem.eql(u8, seq_points, "abcdefghi"));
6186}6145}
6187async fn amain() void {6146fn amain() void {
6188 seq('b');6147 seq('b');
6189 const p = async another() catch unreachable;6148 var f = async another();
6190 seq('e');6149 seq('e');
6191 final_result = await p;6150 final_result = await f;
6192 seq('h');6151 seq('h');
6193}6152}
6194async fn another() i32 {6153fn another() i32 {
6195 seq('c');6154 seq('c');
6196 suspend {6155 suspend {
6197 seq('d');6156 seq('d');
6198 a_promise = @handle();6157 the_frame = @frame();
6199 }6158 }
6200 seq('g');6159 seq('g');
6201 return 1234;6160 return 1234;
...@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {...@@ -6211,31 +6170,156 @@ fn seq(c: u8) void {
6211 {#code_end#}6170 {#code_end#}
6212 <p>6171 <p>
6213 In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application6172 In general, {#syntax#}suspend{#endsyntax#} is lower level than {#syntax#}await{#endsyntax#}. Most application
6214 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop6173 code will use only {#syntax#}async{#endsyntax#} and {#syntax#}await{#endsyntax#}, but event loop
6215 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.6174 implementations will make use of {#syntax#}suspend{#endsyntax#} internally.
6216 </p>6175 </p>
6217 {#header_close#}6176 {#header_close#}
6218 {#header_open|Open Issues#}6177
6178 {#header_open|Async Function Example#}
6219 <p>6179 <p>
6220 There are a few issues with coroutines that are considered unresolved. Best be aware of them,6180 Putting all of this together, here is an example of typical
6221 as the situation is likely to change before 1.0.0:6181 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
6182 </p>
6183 {#code_begin|exe|async#}
6184const std = @import("std");
6185const Allocator = std.mem.Allocator;
6186
6187pub fn main() void {
6188 _ = async amainWrap();
6189
6190 // Typically we would use an event loop to manage resuming async functions,
6191 // but in this example we hard code what the event loop would do,
6192 // to make things deterministic.
6193 resume global_file_frame;
6194 resume global_download_frame;
6195}
6196
6197fn amainWrap() void {
6198 amain() catch |e| {
6199 std.debug.warn("{}\n", e);
6200 if (@errorReturnTrace()) |trace| {
6201 std.debug.dumpStackTrace(trace.*);
6202 }
6203 std.process.exit(1);
6204 };
6205}
6206
6207fn amain() !void {
6208 const allocator = std.heap.direct_allocator;
6209 var download_frame = async fetchUrl(allocator, "https://example.com/");
6210 var awaited_download_frame = false;
6211 errdefer if (!awaited_download_frame) {
6212 if (await download_frame) |r| allocator.free(r) else |_| {}
6213 };
6214
6215 var file_frame = async readFile(allocator, "something.txt");
6216 var awaited_file_frame = false;
6217 errdefer if (!awaited_file_frame) {
6218 if (await file_frame) |r| allocator.free(r) else |_| {}
6219 };
6220
6221 awaited_file_frame = true;
6222 const file_text = try await file_frame;
6223 defer allocator.free(file_text);
6224
6225 awaited_download_frame = true;
6226 const download_text = try await download_frame;
6227 defer allocator.free(download_text);
6228
6229 std.debug.warn("download_text: {}\n", download_text);
6230 std.debug.warn("file_text: {}\n", file_text);
6231}
6232
6233var global_download_frame: anyframe = undefined;
6234fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6235 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6236 errdefer allocator.free(result);
6237 suspend {
6238 global_download_frame = @frame();
6239 }
6240 std.debug.warn("fetchUrl returning\n");
6241 return result;
6242}
6243
6244var global_file_frame: anyframe = undefined;
6245fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6246 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6247 errdefer allocator.free(result);
6248 suspend {
6249 global_file_frame = @frame();
6250 }
6251 std.debug.warn("readFile returning\n");
6252 return result;
6253}
6254 {#code_end#}
6255 <p>
6256 Now we remove the {#syntax#}suspend{#endsyntax#} and {#syntax#}resume{#endsyntax#} code, and
6257 observe the same behavior, with one tiny difference:
6258 </p>
6259 {#code_begin|exe|blocking#}
6260const std = @import("std");
6261const Allocator = std.mem.Allocator;
6262
6263pub fn main() void {
6264 _ = async amainWrap();
6265}
6266
6267fn amainWrap() void {
6268 amain() catch |e| {
6269 std.debug.warn("{}\n", e);
6270 if (@errorReturnTrace()) |trace| {
6271 std.debug.dumpStackTrace(trace.*);
6272 }
6273 std.process.exit(1);
6274 };
6275}
6276
6277fn amain() !void {
6278 const allocator = std.heap.direct_allocator;
6279 var download_frame = async fetchUrl(allocator, "https://example.com/");
6280 var awaited_download_frame = false;
6281 errdefer if (!awaited_download_frame) {
6282 if (await download_frame) |r| allocator.free(r) else |_| {}
6283 };
6284
6285 var file_frame = async readFile(allocator, "something.txt");
6286 var awaited_file_frame = false;
6287 errdefer if (!awaited_file_frame) {
6288 if (await file_frame) |r| allocator.free(r) else |_| {}
6289 };
6290
6291 awaited_file_frame = true;
6292 const file_text = try await file_frame;
6293 defer allocator.free(file_text);
6294
6295 awaited_download_frame = true;
6296 const download_text = try await download_frame;
6297 defer allocator.free(download_text);
6298
6299 std.debug.warn("download_text: {}\n", download_text);
6300 std.debug.warn("file_text: {}\n", file_text);
6301}
6302
6303fn fetchUrl(allocator: *Allocator, url: []const u8) ![]u8 {
6304 const result = try std.mem.dupe(allocator, u8, "this is the downloaded url contents");
6305 errdefer allocator.free(result);
6306 std.debug.warn("fetchUrl returning\n");
6307 return result;
6308}
6309
6310fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
6311 const result = try std.mem.dupe(allocator, u8, "this is the file contents");
6312 errdefer allocator.free(result);
6313 std.debug.warn("readFile returning\n");
6314 return result;
6315}
6316 {#code_end#}
6317 <p>
6318 Previously, the {#syntax#}fetchUrl{#endsyntax#} and {#syntax#}readFile{#endsyntax#} functions suspended,
6319 and were resumed in an order determined by the {#syntax#}main{#endsyntax#} function. Now,
6320 since there are no suspend points, the order of the printed "... returning" messages
6321 is determined by the order of {#syntax#}async{#endsyntax#} callsites.
6222 </p>6322 </p>
6223 <ul>
6224 <li>Async functions have optimizations disabled - even in release modes - due to an
6225 <a href="https://github.com/ziglang/zig/issues/802">LLVM bug</a>.
6226 </li>
6227 <li>
6228 There are some situations where we can know statically that there will not be
6229 memory allocation failure, but Zig still forces us to handle it.
6230 TODO file an issue for this and link it here.
6231 </li>
6232 <li>
6233 Zig does not take advantage of LLVM's allocation elision optimization for
6234 coroutines. It crashed LLVM when I tried to do it the first time. This is
6235 related to the other 2 bullet points here. See
6236 <a href="https://github.com/ziglang/zig/issues/802">#802</a>.
6237 </li>
6238 </ul>
6239 {#header_close#}6323 {#header_close#}
62406324
6241 {#header_close#}6325 {#header_close#}
...@@ -6293,6 +6377,49 @@ comptime {...@@ -6293,6 +6377,49 @@ comptime {
6293 Note: This function is deprecated. Use {#link|@typeInfo#} instead.6377 Note: This function is deprecated. Use {#link|@typeInfo#} instead.
6294 </p>6378 </p>
6295 {#header_close#}6379 {#header_close#}
6380
6381 {#header_open|@asyncCall#}
6382 <pre>{#syntax#}@asyncCall(frame_buffer: []u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre>
6383 <p>
6384 {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer,
6385 which may or may not be an {#link|async function|Async Functions#}.
6386 </p>
6387 <p>
6388 The provided {#syntax#}frame_buffer{#endsyntax#} must be large enough to fit the entire function frame.
6389 This size can be determined with {#link|@frameSize#}. To provide a too-small buffer
6390 invokes safety-checked {#link|Undefined Behavior#}.
6391 </p>
6392 <p>
6393 {#syntax#}result_ptr{#endsyntax#} is optional ({#link|null#} may be provided). If provided,
6394 the function call will write its result directly to the result pointer, which will be available to
6395 read after {#link|await|Async and Await#} completes. Any result location provided to
6396 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
6397 </p>
6398 {#code_begin|test#}
6399const std = @import("std");
6400const assert = std.debug.assert;
6401
6402test "async fn pointer in a struct field" {
6403 var data: i32 = 1;
6404 const Foo = struct {
6405 bar: async fn (*i32) void,
6406 };
6407 var foo = Foo{ .bar = func };
6408 var bytes: [64]u8 = undefined;
6409 const f = @asyncCall(&bytes, {}, foo.bar, &data);
6410 assert(data == 2);
6411 resume f;
6412 assert(data == 4);
6413}
6414
6415async fn func(y: *i32) void {
6416 defer y.* += 2;
6417 y.* += 1;
6418 suspend;
6419}
6420 {#code_end#}
6421 {#header_close#}
6422
6296 {#header_open|@atomicLoad#}6423 {#header_open|@atomicLoad#}
6297 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>6424 <pre>{#syntax#}@atomicLoad(comptime T: type, ptr: *const T, comptime ordering: builtin.AtomicOrder) T{#endsyntax#}</pre>
6298 <p>6425 <p>
...@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}...@@ -6883,6 +7010,44 @@ export fn @"A function name that is a complete sentence."() void {}
6883 {#see_also|@intToFloat#}7010 {#see_also|@intToFloat#}
6884 {#header_close#}7011 {#header_close#}
68857012
7013 {#header_open|@frame#}
7014 <pre>{#syntax#}@frame() *@Frame(func){#endsyntax#}</pre>
7015 <p>
7016 This function returns a pointer to the frame for a given function. This type
7017 can be {#link|implicitly cast|Implicit Casts#} to {#syntax#}anyframe->T{#endsyntax#} and
7018 to {#syntax#}anyframe{#endsyntax#}, where {#syntax#}T{#endsyntax#} is the return type
7019 of the function in scope.
7020 </p>
7021 <p>
7022 This function does not mark a suspension point, but it does cause the function in scope
7023 to become an {#link|async function|Async Functions#}.
7024 </p>
7025 {#header_close#}
7026
7027 {#header_open|@Frame#}
7028 <pre>{#syntax#}@Frame(func: var) type{#endsyntax#}</pre>
7029 <p>
7030 This function returns the frame type of a function. This works for {#link|Async Functions#}
7031 as well as any function without a specific calling convention.
7032 </p>
7033 <p>
7034 This type is suitable to be used as the return type of {#link|async|Async and Await#} which
7035 allows one to, for example, heap-allocate an async function frame:
7036 </p>
7037 {#code_begin|test#}
7038const std = @import("std");
7039
7040test "heap allocated frame" {
7041 const frame = try std.heap.direct_allocator.create(@Frame(func));
7042 frame.* = async func();
7043}
7044
7045fn func() void {
7046 suspend;
7047}
7048 {#code_end#}
7049 {#header_close#}
7050
6886 {#header_open|@frameAddress#}7051 {#header_open|@frameAddress#}
6887 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>7052 <pre>{#syntax#}@frameAddress() usize{#endsyntax#}</pre>
6888 <p>7053 <p>
...@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}...@@ -6898,14 +7063,14 @@ export fn @"A function name that is a complete sentence."() void {}
6898 </p>7063 </p>
6899 {#header_close#}7064 {#header_close#}
69007065
6901 {#header_open|@handle#}7066 {#header_open|@frameSize#}
6902 <pre>{#syntax#}@handle(){#endsyntax#}</pre>7067 <pre>{#syntax#}@frameSize() usize{#endsyntax#}</pre>
6903 <p>7068 <p>
6904 This function returns a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}7069 This is the same as {#syntax#}@sizeOf(@Frame(func)){#endsyntax#}, where {#syntax#}func{#endsyntax#}
6905 is the return type of the async function in scope.7070 may be runtime-known.
6906 </p>7071 </p>
6907 <p>7072 <p>
6908 This function is only valid within an async function scope.7073 This function is typically used in conjunction with {#link|@asyncCall#}.
6909 </p>7074 </p>
6910 {#header_close#}7075 {#header_close#}
69117076
...@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {...@@ -8045,8 +8210,7 @@ pub fn build(b: *Builder) void {
8045 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:8210 <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
8046 <ul>8211 <ul>
8047 <li>All {#link|Thread Local Variables#} are treated as {#link|Global Variables#}.</li>8212 <li>All {#link|Thread Local Variables#} are treated as {#link|Global Variables#}.</li>
8048 <li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.8213 <li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
8049 TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
8050 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}8214 <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
8051 and therefore various userland APIs which read this variable become more efficient.8215 and therefore various userland APIs which read this variable become more efficient.
8052 For example {#syntax#}std.Mutex{#endsyntax#} becomes8216 For example {#syntax#}std.Mutex{#endsyntax#} becomes
...@@ -9794,7 +9958,6 @@ PrimaryExpr...@@ -9794,7 +9958,6 @@ PrimaryExpr
9794 &lt;- AsmExpr9958 &lt;- AsmExpr
9795 / IfExpr9959 / IfExpr
9796 / KEYWORD_break BreakLabel? Expr?9960 / KEYWORD_break BreakLabel? Expr?
9797 / KEYWORD_cancel Expr
9798 / KEYWORD_comptime Expr9961 / KEYWORD_comptime Expr
9799 / KEYWORD_continue BreakLabel?9962 / KEYWORD_continue BreakLabel?
9800 / KEYWORD_resume Expr9963 / KEYWORD_resume Expr
...@@ -9825,7 +9988,7 @@ TypeExpr &lt;- PrefixTypeOp* ErrorUnionExpr...@@ -9825,7 +9988,7 @@ TypeExpr &lt;- PrefixTypeOp* ErrorUnionExpr
9825ErrorUnionExpr &lt;- SuffixExpr (EXCLAMATIONMARK TypeExpr)?9988ErrorUnionExpr &lt;- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
98269989
9827SuffixExpr9990SuffixExpr
9828 &lt;- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments9991 &lt;- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
9829 / PrimaryTypeExpr (SuffixOp / FnCallArguments)*9992 / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
98309993
9831PrimaryTypeExpr9994PrimaryTypeExpr
...@@ -9901,7 +10064,7 @@ FnCC...@@ -9901,7 +10064,7 @@ FnCC
9901 &lt;- KEYWORD_nakedcc10064 &lt;- KEYWORD_nakedcc
9902 / KEYWORD_stdcallcc10065 / KEYWORD_stdcallcc
9903 / KEYWORD_extern10066 / KEYWORD_extern
9904 / KEYWORD_async (LARROW TypeExpr RARROW)?10067 / KEYWORD_async
990510068
9906ParamDecl &lt;- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType10069ParamDecl &lt;- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
990710070
...@@ -10006,8 +10169,6 @@ SuffixOp...@@ -10006,8 +10169,6 @@ SuffixOp
10006 / DOTASTERISK10169 / DOTASTERISK
10007 / DOTQUESTIONMARK10170 / DOTQUESTIONMARK
1000810171
10009AsyncPrefix &lt;- KEYWORD_async (LARROW PrefixExpr RARROW)?
10010
10011FnCallArguments &lt;- LPAREN ExprList RPAREN10172FnCallArguments &lt;- LPAREN ExprList RPAREN
1001210173
10013# Ptr specific10174# Ptr specific
...@@ -10150,7 +10311,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word...@@ -10150,7 +10311,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word
10150KEYWORD_async &lt;- 'async' end_of_word10311KEYWORD_async &lt;- 'async' end_of_word
10151KEYWORD_await &lt;- 'await' end_of_word10312KEYWORD_await &lt;- 'await' end_of_word
10152KEYWORD_break &lt;- 'break' end_of_word10313KEYWORD_break &lt;- 'break' end_of_word
10153KEYWORD_cancel &lt;- 'cancel' end_of_word
10154KEYWORD_catch &lt;- 'catch' end_of_word10314KEYWORD_catch &lt;- 'catch' end_of_word
10155KEYWORD_comptime &lt;- 'comptime' end_of_word10315KEYWORD_comptime &lt;- 'comptime' end_of_word
10156KEYWORD_const &lt;- 'const' end_of_word10316KEYWORD_const &lt;- 'const' end_of_word
...@@ -10195,7 +10355,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word...@@ -10195,7 +10355,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word
10195KEYWORD_while &lt;- 'while' end_of_word10355KEYWORD_while &lt;- 'while' end_of_word
1019610356
10197keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm10357keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm
10198 / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel10358 / KEYWORD_async / KEYWORD_await / KEYWORD_break
10199 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue10359 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
10200 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer10360 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
10201 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false10361 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
src-self-hosted/ir.zig-15
...@@ -1181,7 +1181,6 @@ pub const Builder = struct {...@@ -1181,7 +1181,6 @@ pub const Builder = struct {
1181 ast.Node.Id.ErrorTag => return error.Unimplemented,1181 ast.Node.Id.ErrorTag => return error.Unimplemented,
1182 ast.Node.Id.AsmInput => return error.Unimplemented,1182 ast.Node.Id.AsmInput => return error.Unimplemented,
1183 ast.Node.Id.AsmOutput => return error.Unimplemented,1183 ast.Node.Id.AsmOutput => return error.Unimplemented,
1184 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
1185 ast.Node.Id.ParamDecl => return error.Unimplemented,1184 ast.Node.Id.ParamDecl => return error.Unimplemented,
1186 ast.Node.Id.FieldInitializer => return error.Unimplemented,1185 ast.Node.Id.FieldInitializer => return error.Unimplemented,
1187 ast.Node.Id.EnumLiteral => return error.Unimplemented,1186 ast.Node.Id.EnumLiteral => return error.Unimplemented,
...@@ -1904,20 +1903,6 @@ pub const Builder = struct {...@@ -1904,20 +1903,6 @@ pub const Builder = struct {
1904 }1903 }
1905 return error.Unimplemented;1904 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
1921 }1906 }
19221907
1923 const Ident = union(enum) {1908 const Ident = union(enum) {
src-self-hosted/link.zig+1-1
...@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {...@@ -627,7 +627,7 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
627627
628fn addFnObjects(ctx: *Context) !void {628fn addFnObjects(ctx: *Context) !void {
629 // at this point it's guaranteed nobody else has this lock, so we circumvent it629 // at this point it's guaranteed nobody else has this lock, so we circumvent it
630 // and avoid having to be a coroutine630 // and avoid having to be an async function
631 const fn_link_set = &ctx.comp.fn_link_set.private_data;631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
632632
633 var it = fn_link_set.first;633 var it = fn_link_set.first;
src-self-hosted/main.zig+9-12
...@@ -52,7 +52,7 @@ const Command = struct {...@@ -52,7 +52,7 @@ const Command = struct {
5252
53pub fn main() !void {53pub fn main() !void {
54 // This allocator needs to be thread-safe because we use it for the event.Loop54 // This allocator needs to be thread-safe because we use it for the event.Loop
55 // which multiplexes coroutines onto kernel threads.55 // which multiplexes async functions onto kernel threads.
56 // libc allocator is guaranteed to have this property.56 // libc allocator is guaranteed to have this property.
57 const allocator = std.heap.c_allocator;57 const allocator = std.heap.c_allocator;
5858
...@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -466,8 +466,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
466 comp.link_objects = link_objects;466 comp.link_objects = link_objects;
467467
468 comp.start();468 comp.start();
469 const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);469 // TODO const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color);
470 defer cancel process_build_events_handle;
471 loop.run();470 loop.run();
472}471}
473472
...@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -578,8 +577,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
578 var zig_compiler = try ZigCompiler.init(&loop);577 var zig_compiler = try ZigCompiler.init(&loop);
579 defer zig_compiler.deinit();578 defer zig_compiler.deinit();
580579
581 const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);580 // TODO const handle = try async<loop.allocator> findLibCAsync(&zig_compiler);
582 defer cancel handle;
583581
584 loop.run();582 loop.run();
585}583}
...@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -663,13 +661,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
663 defer loop.deinit();661 defer loop.deinit();
664662
665 var result: FmtError!void = undefined;663 var result: FmtError!void = undefined;
666 const main_handle = try async<allocator> asyncFmtMainChecked(664 // TODO const main_handle = try async<allocator> asyncFmtMainChecked(
667 &result,665 // TODO &result,
668 &loop,666 // TODO &loop,
669 &flags,667 // TODO &flags,
670 color,668 // TODO color,
671 );669 // TODO );
672 defer cancel main_handle;
673 loop.run();670 loop.run();
674 return result;671 return result;
675}672}
src-self-hosted/stage1.zig+2-1
...@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {...@@ -142,7 +142,8 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
142 return Error.None;142 return Error.None;
143}143}
144144
145// TODO: just use the actual self-hosted zig fmt. Until the coroutine rewrite, we use a blocking implementation.145// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377,
146// we use a blocking implementation.
146export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {147export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int {
147 if (std.debug.runtime_safety) {148 if (std.debug.runtime_safety) {
148 fmtMain(argc, argv) catch unreachable;149 fmtMain(argc, argv) catch unreachable;
src-self-hosted/translate_c.zig+1-2
...@@ -1037,7 +1037,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {...@@ -1037,7 +1037,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
1037 .op = ast.Node.SuffixOp.Op{1037 .op = ast.Node.SuffixOp.Op{
1038 .Call = ast.Node.SuffixOp.Op.Call{1038 .Call = ast.Node.SuffixOp.Op.Call{
1039 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),1039 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
1040 .async_attr = null,1040 .async_token = null,
1041 },1041 },
1042 },1042 },
1043 .rtoken = undefined, // set after appending args1043 .rtoken = undefined, // set after appending args
...@@ -1355,7 +1355,6 @@ fn finishTransFnProto(...@@ -1355,7 +1355,6 @@ fn finishTransFnProto(
1355 .var_args_token = null, // TODO this field is broken in the AST data model1355 .var_args_token = null, // TODO this field is broken in the AST data model
1356 .extern_export_inline_token = extern_export_inline_tok,1356 .extern_export_inline_token = extern_export_inline_tok,
1357 .cc_token = cc_tok,1357 .cc_token = cc_tok,
1358 .async_attr = null,
1359 .body_node = null,1358 .body_node = null,
1360 .lib_name = null,1359 .lib_name = null,
1361 .align_expr = null,1360 .align_expr = null,
src/all_types.hpp+162-217
...@@ -35,6 +35,7 @@ struct ConstExprValue;...@@ -35,6 +35,7 @@ struct ConstExprValue;
35struct IrInstruction;35struct IrInstruction;
36struct IrInstructionCast;36struct IrInstructionCast;
37struct IrInstructionAllocaGen;37struct IrInstructionAllocaGen;
38struct IrInstructionCallGen;
38struct IrBasicBlock;39struct IrBasicBlock;
39struct ScopeDecls;40struct ScopeDecls;
40struct ZigWindowsSDK;41struct ZigWindowsSDK;
...@@ -70,20 +71,10 @@ struct IrExecutable {...@@ -70,20 +71,10 @@ struct IrExecutable {
70 Scope *begin_scope;71 Scope *begin_scope;
71 ZigList<Tld *> tld_list;72 ZigList<Tld *> tld_list;
7273
73 IrInstruction *coro_handle;
74 IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
75 IrInstruction *coro_result_ptr_field_ptr;
76 IrInstruction *coro_result_field_ptr;
77 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
78 IrBasicBlock *coro_early_final;
79 IrBasicBlock *coro_normal_final;
80 IrBasicBlock *coro_suspend_block;
81 IrBasicBlock *coro_final_cleanup_block;
82 ZigVar *coro_allocator_var;
83
84 bool invalid;74 bool invalid;
85 bool is_inline;75 bool is_inline;
86 bool is_generic_instantiation;76 bool is_generic_instantiation;
77 bool need_err_code_spill;
87};78};
8879
89enum OutType {80enum OutType {
...@@ -485,11 +476,10 @@ enum NodeType {...@@ -485,11 +476,10 @@ enum NodeType {
485 NodeTypeIfErrorExpr,476 NodeTypeIfErrorExpr,
486 NodeTypeIfOptional,477 NodeTypeIfOptional,
487 NodeTypeErrorSetDecl,478 NodeTypeErrorSetDecl,
488 NodeTypeCancel,
489 NodeTypeResume,479 NodeTypeResume,
490 NodeTypeAwaitExpr,480 NodeTypeAwaitExpr,
491 NodeTypeSuspend,481 NodeTypeSuspend,
492 NodeTypePromiseType,482 NodeTypeAnyFrameType,
493 NodeTypeEnumLiteral,483 NodeTypeEnumLiteral,
494};484};
495485
...@@ -522,7 +512,6 @@ struct AstNodeFnProto {...@@ -522,7 +512,6 @@ struct AstNodeFnProto {
522 AstNode *section_expr;512 AstNode *section_expr;
523513
524 bool auto_err_set;514 bool auto_err_set;
525 AstNode *async_allocator_type;
526};515};
527516
528struct AstNodeFnDef {517struct AstNodeFnDef {
...@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {...@@ -657,7 +646,6 @@ struct AstNodeFnCallExpr {
657 bool is_builtin;646 bool is_builtin;
658 bool is_async;647 bool is_async;
659 bool seen; // used by @compileLog648 bool seen; // used by @compileLog
660 AstNode *async_allocator;
661};649};
662650
663struct AstNodeArrayAccessExpr {651struct AstNodeArrayAccessExpr {
...@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {...@@ -922,10 +910,6 @@ struct AstNodeBreakExpr {
922 AstNode *expr; // may be null910 AstNode *expr; // may be null
923};911};
924912
925struct AstNodeCancelExpr {
926 AstNode *expr;
927};
928
929struct AstNodeResumeExpr {913struct AstNodeResumeExpr {
930 AstNode *expr;914 AstNode *expr;
931};915};
...@@ -949,7 +933,7 @@ struct AstNodeSuspend {...@@ -949,7 +933,7 @@ struct AstNodeSuspend {
949 AstNode *block;933 AstNode *block;
950};934};
951935
952struct AstNodePromiseType {936struct AstNodeAnyFrameType {
953 AstNode *payload_type; // can be NULL937 AstNode *payload_type; // can be NULL
954};938};
955939
...@@ -1014,13 +998,16 @@ struct AstNode {...@@ -1014,13 +998,16 @@ struct AstNode {
1014 AstNodeInferredArrayType inferred_array_type;998 AstNodeInferredArrayType inferred_array_type;
1015 AstNodeErrorType error_type;999 AstNodeErrorType error_type;
1016 AstNodeErrorSetDecl err_set_decl;1000 AstNodeErrorSetDecl err_set_decl;
1017 AstNodeCancelExpr cancel_expr;
1018 AstNodeResumeExpr resume_expr;1001 AstNodeResumeExpr resume_expr;
1019 AstNodeAwaitExpr await_expr;1002 AstNodeAwaitExpr await_expr;
1020 AstNodeSuspend suspend;1003 AstNodeSuspend suspend;
1021 AstNodePromiseType promise_type;1004 AstNodeAnyFrameType anyframe_type;
1022 AstNodeEnumLiteral enum_literal;1005 AstNodeEnumLiteral enum_literal;
1023 } data;1006 } data;
1007
1008 // This is a function for use in the debugger to print
1009 // the source location.
1010 void src();
1024};1011};
10251012
1026// this struct is allocated with allocate_nonzero1013// this struct is allocated with allocate_nonzero
...@@ -1047,7 +1034,6 @@ struct FnTypeId {...@@ -1047,7 +1034,6 @@ struct FnTypeId {
1047 bool is_var_args;1034 bool is_var_args;
1048 CallingConvention cc;1035 CallingConvention cc;
1049 uint32_t alignment;1036 uint32_t alignment;
1050 ZigType *async_allocator_type;
1051};1037};
10521038
1053uint32_t fn_type_id_hash(FnTypeId*);1039uint32_t fn_type_id_hash(FnTypeId*);
...@@ -1095,6 +1081,7 @@ struct TypeStructField {...@@ -1095,6 +1081,7 @@ struct TypeStructField {
1095 ConstExprValue *init_val; // null and then memoized1081 ConstExprValue *init_val; // null and then memoized
1096 uint32_t bit_offset_in_host; // offset from the memory at gen_index1082 uint32_t bit_offset_in_host; // offset from the memory at gen_index
1097 uint32_t host_int_bytes; // size of host integer1083 uint32_t host_int_bytes; // size of host integer
1084 uint32_t align;
1098};1085};
10991086
1100enum ResolveStatus {1087enum ResolveStatus {
...@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {...@@ -1156,6 +1143,8 @@ struct ZigTypeOptional {
1156struct ZigTypeErrorUnion {1143struct ZigTypeErrorUnion {
1157 ZigType *err_set_type;1144 ZigType *err_set_type;
1158 ZigType *payload_type;1145 ZigType *payload_type;
1146 size_t pad_bytes;
1147 LLVMTypeRef pad_llvm_type;
1159};1148};
11601149
1161struct ZigTypeErrorSet {1150struct ZigTypeErrorSet {
...@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {...@@ -1241,11 +1230,6 @@ struct ZigTypeBoundFn {
1241 ZigType *fn_type;1230 ZigType *fn_type;
1242};1231};
12431232
1244struct ZigTypePromise {
1245 // null if `promise` instead of `promise->T`
1246 ZigType *result_type;
1247};
1248
1249struct ZigTypeVector {1233struct ZigTypeVector {
1250 // The type must be a pointer, integer, or float1234 // The type must be a pointer, integer, or float
1251 ZigType *elem_type;1235 ZigType *elem_type;
...@@ -1276,7 +1260,8 @@ enum ZigTypeId {...@@ -1276,7 +1260,8 @@ enum ZigTypeId {
1276 ZigTypeIdBoundFn,1260 ZigTypeIdBoundFn,
1277 ZigTypeIdArgTuple,1261 ZigTypeIdArgTuple,
1278 ZigTypeIdOpaque,1262 ZigTypeIdOpaque,
1279 ZigTypeIdPromise,1263 ZigTypeIdFnFrame,
1264 ZigTypeIdAnyFrame,
1280 ZigTypeIdVector,1265 ZigTypeIdVector,
1281 ZigTypeIdEnumLiteral,1266 ZigTypeIdEnumLiteral,
1282};1267};
...@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {...@@ -1291,6 +1276,15 @@ struct ZigTypeOpaque {
1291 Buf *bare_name;1276 Buf *bare_name;
1292};1277};
12931278
1279struct ZigTypeFnFrame {
1280 ZigFn *fn;
1281 ZigType *locals_struct;
1282};
1283
1284struct ZigTypeAnyFrame {
1285 ZigType *result_type; // null if `anyframe` instead of `anyframe->T`
1286};
1287
1294struct ZigType {1288struct ZigType {
1295 ZigTypeId id;1289 ZigTypeId id;
1296 Buf name;1290 Buf name;
...@@ -1314,16 +1308,16 @@ struct ZigType {...@@ -1314,16 +1308,16 @@ struct ZigType {
1314 ZigTypeUnion unionation;1308 ZigTypeUnion unionation;
1315 ZigTypeFn fn;1309 ZigTypeFn fn;
1316 ZigTypeBoundFn bound_fn;1310 ZigTypeBoundFn bound_fn;
1317 ZigTypePromise promise;
1318 ZigTypeVector vector;1311 ZigTypeVector vector;
1319 ZigTypeOpaque opaque;1312 ZigTypeOpaque opaque;
1313 ZigTypeFnFrame frame;
1314 ZigTypeAnyFrame any_frame;
1320 } data;1315 } data;
13211316
1322 // use these fields to make sure we don't duplicate type table entries for the same type1317 // use these fields to make sure we don't duplicate type table entries for the same type
1323 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]1318 ZigType *pointer_parent[2]; // [0 - mut, 1 - const]
1324 ZigType *optional_parent;1319 ZigType *optional_parent;
1325 ZigType *promise_parent;1320 ZigType *any_frame_parent;
1326 ZigType *promise_frame_parent;
1327 // If we generate a constant name value for this type, we memoize it here.1321 // If we generate a constant name value for this type, we memoize it here.
1328 // The type of this is array1322 // The type of this is array
1329 ConstExprValue *cached_const_name_val;1323 ConstExprValue *cached_const_name_val;
...@@ -1359,7 +1353,6 @@ struct GlobalExport {...@@ -1359,7 +1353,6 @@ struct GlobalExport {
1359};1353};
13601354
1361struct ZigFn {1355struct ZigFn {
1362 CodeGen *codegen;
1363 LLVMValueRef llvm_value;1356 LLVMValueRef llvm_value;
1364 const char *llvm_name;1357 const char *llvm_name;
1365 AstNode *proto_node;1358 AstNode *proto_node;
...@@ -1368,7 +1361,17 @@ struct ZigFn {...@@ -1368,7 +1361,17 @@ struct ZigFn {
1368 Scope *child_scope; // parent is scope for last parameter1361 Scope *child_scope; // parent is scope for last parameter
1369 ScopeBlock *def_scope; // parent is child_scope1362 ScopeBlock *def_scope; // parent is child_scope
1370 Buf symbol_name;1363 Buf symbol_name;
1371 ZigType *type_entry; // function type1364 // This is the function type assuming the function does not suspend.
1365 // Note that for an async function, this can be shared with non-async functions. So the value here
1366 // should only be read for things in common between non-async and async function types.
1367 ZigType *type_entry;
1368 // For normal functions one could use the type_entry->raw_type_ref and type_entry->raw_di_type.
1369 // However for functions that suspend, those values could possibly be their non-suspending equivalents.
1370 // So these values should be preferred.
1371 LLVMTypeRef raw_type_ref;
1372 ZigLLVMDIType *raw_di_type;
1373
1374 ZigType *frame_type;
1372 // in the case of normal functions this is the implicit return type1375 // in the case of normal functions this is the implicit return type
1373 // in the case of async functions this is the implicit return type according to the1376 // in the case of async functions this is the implicit return type according to the
1374 // zig source code, not according to zig ir1377 // zig source code, not according to zig ir
...@@ -1379,6 +1382,7 @@ struct ZigFn {...@@ -1379,6 +1382,7 @@ struct ZigFn {
1379 size_t prealloc_backward_branch_quota;1382 size_t prealloc_backward_branch_quota;
1380 AstNode **param_source_nodes;1383 AstNode **param_source_nodes;
1381 Buf **param_names;1384 Buf **param_names;
1385 IrInstruction *err_code_spill;
13821386
1383 AstNode *fn_no_inline_set_node;1387 AstNode *fn_no_inline_set_node;
1384 AstNode *fn_static_eval_set_node;1388 AstNode *fn_static_eval_set_node;
...@@ -1390,8 +1394,11 @@ struct ZigFn {...@@ -1390,8 +1394,11 @@ struct ZigFn {
1390 AstNode *set_alignstack_node;1394 AstNode *set_alignstack_node;
13911395
1392 AstNode *set_cold_node;1396 AstNode *set_cold_node;
1397 const AstNode *inferred_async_node;
1398 ZigFn *inferred_async_fn;
13931399
1394 ZigList<GlobalExport> export_list;1400 ZigList<GlobalExport> export_list;
1401 ZigList<IrInstructionCallGen *> call_list;
13951402
1396 LLVMValueRef valgrind_client_request_array;1403 LLVMValueRef valgrind_client_request_array;
13971404
...@@ -1442,8 +1449,6 @@ enum BuiltinFnId {...@@ -1442,8 +1449,6 @@ enum BuiltinFnId {
1442 BuiltinFnIdErrName,1449 BuiltinFnIdErrName,
1443 BuiltinFnIdBreakpoint,1450 BuiltinFnIdBreakpoint,
1444 BuiltinFnIdReturnAddress,1451 BuiltinFnIdReturnAddress,
1445 BuiltinFnIdFrameAddress,
1446 BuiltinFnIdHandle,
1447 BuiltinFnIdEmbedFile,1452 BuiltinFnIdEmbedFile,
1448 BuiltinFnIdCmpxchgWeak,1453 BuiltinFnIdCmpxchgWeak,
1449 BuiltinFnIdCmpxchgStrong,1454 BuiltinFnIdCmpxchgStrong,
...@@ -1499,6 +1504,7 @@ enum BuiltinFnId {...@@ -1499,6 +1504,7 @@ enum BuiltinFnId {
1499 BuiltinFnIdInlineCall,1504 BuiltinFnIdInlineCall,
1500 BuiltinFnIdNoInlineCall,1505 BuiltinFnIdNoInlineCall,
1501 BuiltinFnIdNewStackCall,1506 BuiltinFnIdNewStackCall,
1507 BuiltinFnIdAsyncCall,
1502 BuiltinFnIdTypeId,1508 BuiltinFnIdTypeId,
1503 BuiltinFnIdShlExact,1509 BuiltinFnIdShlExact,
1504 BuiltinFnIdShrExact,1510 BuiltinFnIdShrExact,
...@@ -1514,6 +1520,10 @@ enum BuiltinFnId {...@@ -1514,6 +1520,10 @@ enum BuiltinFnId {
1514 BuiltinFnIdAtomicLoad,1520 BuiltinFnIdAtomicLoad,
1515 BuiltinFnIdHasDecl,1521 BuiltinFnIdHasDecl,
1516 BuiltinFnIdUnionInit,1522 BuiltinFnIdUnionInit,
1523 BuiltinFnIdFrameAddress,
1524 BuiltinFnIdFrameType,
1525 BuiltinFnIdFrameHandle,
1526 BuiltinFnIdFrameSize,
1517};1527};
15181528
1519struct BuiltinFnEntry {1529struct BuiltinFnEntry {
...@@ -1541,6 +1551,12 @@ enum PanicMsgId {...@@ -1541,6 +1551,12 @@ enum PanicMsgId {
1541 PanicMsgIdBadEnumValue,1551 PanicMsgIdBadEnumValue,
1542 PanicMsgIdFloatToInt,1552 PanicMsgIdFloatToInt,
1543 PanicMsgIdPtrCastNull,1553 PanicMsgIdPtrCastNull,
1554 PanicMsgIdBadResume,
1555 PanicMsgIdBadAwait,
1556 PanicMsgIdBadReturn,
1557 PanicMsgIdResumedAnAwaitingFn,
1558 PanicMsgIdFrameTooSmall,
1559 PanicMsgIdResumedFnPendingAwait,
15441560
1545 PanicMsgIdCount,1561 PanicMsgIdCount,
1546};1562};
...@@ -1701,7 +1717,13 @@ struct CodeGen {...@@ -1701,7 +1717,13 @@ struct CodeGen {
1701 LLVMTargetMachineRef target_machine;1717 LLVMTargetMachineRef target_machine;
1702 ZigLLVMDIFile *dummy_di_file;1718 ZigLLVMDIFile *dummy_di_file;
1703 LLVMValueRef cur_ret_ptr;1719 LLVMValueRef cur_ret_ptr;
1720 LLVMValueRef cur_frame_ptr;
1704 LLVMValueRef cur_fn_val;1721 LLVMValueRef cur_fn_val;
1722 LLVMValueRef cur_async_switch_instr;
1723 LLVMValueRef cur_async_resume_index_ptr;
1724 LLVMValueRef cur_async_awaiter_ptr;
1725 LLVMBasicBlockRef cur_preamble_llvm_block;
1726 size_t cur_resume_block_count;
1705 LLVMValueRef cur_err_ret_trace_val_arg;1727 LLVMValueRef cur_err_ret_trace_val_arg;
1706 LLVMValueRef cur_err_ret_trace_val_stack;1728 LLVMValueRef cur_err_ret_trace_val_stack;
1707 LLVMValueRef memcpy_fn_val;1729 LLVMValueRef memcpy_fn_val;
...@@ -1709,28 +1731,16 @@ struct CodeGen {...@@ -1709,28 +1731,16 @@ struct CodeGen {
1709 LLVMValueRef trap_fn_val;1731 LLVMValueRef trap_fn_val;
1710 LLVMValueRef return_address_fn_val;1732 LLVMValueRef return_address_fn_val;
1711 LLVMValueRef frame_address_fn_val;1733 LLVMValueRef frame_address_fn_val;
1712 LLVMValueRef coro_destroy_fn_val;
1713 LLVMValueRef coro_id_fn_val;
1714 LLVMValueRef coro_alloc_fn_val;
1715 LLVMValueRef coro_size_fn_val;
1716 LLVMValueRef coro_begin_fn_val;
1717 LLVMValueRef coro_suspend_fn_val;
1718 LLVMValueRef coro_end_fn_val;
1719 LLVMValueRef coro_free_fn_val;
1720 LLVMValueRef coro_resume_fn_val;
1721 LLVMValueRef coro_save_fn_val;
1722 LLVMValueRef coro_promise_fn_val;
1723 LLVMValueRef coro_alloc_helper_fn_val;
1724 LLVMValueRef coro_frame_fn_val;
1725 LLVMValueRef merge_err_ret_traces_fn_val;
1726 LLVMValueRef add_error_return_trace_addr_fn_val;1734 LLVMValueRef add_error_return_trace_addr_fn_val;
1727 LLVMValueRef stacksave_fn_val;1735 LLVMValueRef stacksave_fn_val;
1728 LLVMValueRef stackrestore_fn_val;1736 LLVMValueRef stackrestore_fn_val;
1729 LLVMValueRef write_register_fn_val;1737 LLVMValueRef write_register_fn_val;
1738 LLVMValueRef merge_err_ret_traces_fn_val;
1730 LLVMValueRef sp_md_node;1739 LLVMValueRef sp_md_node;
1731 LLVMValueRef err_name_table;1740 LLVMValueRef err_name_table;
1732 LLVMValueRef safety_crash_err_fn;1741 LLVMValueRef safety_crash_err_fn;
1733 LLVMValueRef return_err_fn;1742 LLVMValueRef return_err_fn;
1743 LLVMTypeRef anyframe_fn_type;
17341744
1735 // reminder: hash tables must be initialized before use1745 // reminder: hash tables must be initialized before use
1736 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;1746 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
...@@ -1797,12 +1807,12 @@ struct CodeGen {...@@ -1797,12 +1807,12 @@ struct CodeGen {
1797 ZigType *entry_var;1807 ZigType *entry_var;
1798 ZigType *entry_global_error_set;1808 ZigType *entry_global_error_set;
1799 ZigType *entry_arg_tuple;1809 ZigType *entry_arg_tuple;
1800 ZigType *entry_promise;
1801 ZigType *entry_enum_literal;1810 ZigType *entry_enum_literal;
1811 ZigType *entry_any_frame;
1802 } builtin_types;1812 } builtin_types;
1813
1803 ZigType *align_amt_type;1814 ZigType *align_amt_type;
1804 ZigType *stack_trace_type;1815 ZigType *stack_trace_type;
1805 ZigType *ptr_to_stack_trace_type;
1806 ZigType *err_tag_type;1816 ZigType *err_tag_type;
1807 ZigType *test_fn_type;1817 ZigType *test_fn_type;
18081818
...@@ -1938,6 +1948,7 @@ struct ZigVar {...@@ -1938,6 +1948,7 @@ struct ZigVar {
1938 ZigType *var_type;1948 ZigType *var_type;
1939 LLVMValueRef value_ref;1949 LLVMValueRef value_ref;
1940 IrInstruction *is_comptime;1950 IrInstruction *is_comptime;
1951 IrInstruction *ptr_instruction;
1941 // which node is the declaration of the variable1952 // which node is the declaration of the variable
1942 AstNode *decl_node;1953 AstNode *decl_node;
1943 ZigLLVMDILocalVariable *di_loc_var;1954 ZigLLVMDILocalVariable *di_loc_var;
...@@ -1985,7 +1996,6 @@ enum ScopeId {...@@ -1985,7 +1996,6 @@ enum ScopeId {
1985 ScopeIdSuspend,1996 ScopeIdSuspend,
1986 ScopeIdFnDef,1997 ScopeIdFnDef,
1987 ScopeIdCompTime,1998 ScopeIdCompTime,
1988 ScopeIdCoroPrelude,
1989 ScopeIdRuntime,1999 ScopeIdRuntime,
1990};2000};
19912001
...@@ -2109,7 +2119,6 @@ struct ScopeRuntime {...@@ -2109,7 +2119,6 @@ struct ScopeRuntime {
2109struct ScopeSuspend {2119struct ScopeSuspend {
2110 Scope base;2120 Scope base;
21112121
2112 IrBasicBlock *resume_block;
2113 bool reported_err;2122 bool reported_err;
2114};2123};
21152124
...@@ -2128,12 +2137,6 @@ struct ScopeFnDef {...@@ -2128,12 +2137,6 @@ struct ScopeFnDef {
2128 ZigFn *fn_entry;2137 ZigFn *fn_entry;
2129};2138};
21302139
2131// This scope is created to indicate that the code in the scope
2132// is auto-generated coroutine prelude stuff.
2133struct ScopeCoroPrelude {
2134 Scope base;
2135};
2136
2137// synchronized with code in define_builtin_compile_vars2140// synchronized with code in define_builtin_compile_vars
2138enum AtomicOrder {2141enum AtomicOrder {
2139 AtomicOrderUnordered,2142 AtomicOrderUnordered,
...@@ -2231,7 +2234,7 @@ enum IrInstructionId {...@@ -2231,7 +2234,7 @@ enum IrInstructionId {
2231 IrInstructionIdSetRuntimeSafety,2234 IrInstructionIdSetRuntimeSafety,
2232 IrInstructionIdSetFloatMode,2235 IrInstructionIdSetFloatMode,
2233 IrInstructionIdArrayType,2236 IrInstructionIdArrayType,
2234 IrInstructionIdPromiseType,2237 IrInstructionIdAnyFrameType,
2235 IrInstructionIdSliceType,2238 IrInstructionIdSliceType,
2236 IrInstructionIdGlobalAsm,2239 IrInstructionIdGlobalAsm,
2237 IrInstructionIdAsm,2240 IrInstructionIdAsm,
...@@ -2278,7 +2281,10 @@ enum IrInstructionId {...@@ -2278,7 +2281,10 @@ enum IrInstructionId {
2278 IrInstructionIdBreakpoint,2281 IrInstructionIdBreakpoint,
2279 IrInstructionIdReturnAddress,2282 IrInstructionIdReturnAddress,
2280 IrInstructionIdFrameAddress,2283 IrInstructionIdFrameAddress,
2281 IrInstructionIdHandle,2284 IrInstructionIdFrameHandle,
2285 IrInstructionIdFrameType,
2286 IrInstructionIdFrameSizeSrc,
2287 IrInstructionIdFrameSizeGen,
2282 IrInstructionIdAlignOf,2288 IrInstructionIdAlignOf,
2283 IrInstructionIdOverflowOp,2289 IrInstructionIdOverflowOp,
2284 IrInstructionIdTestErrSrc,2290 IrInstructionIdTestErrSrc,
...@@ -2321,35 +2327,16 @@ enum IrInstructionId {...@@ -2321,35 +2327,16 @@ enum IrInstructionId {
2321 IrInstructionIdImplicitCast,2327 IrInstructionIdImplicitCast,
2322 IrInstructionIdResolveResult,2328 IrInstructionIdResolveResult,
2323 IrInstructionIdResetResult,2329 IrInstructionIdResetResult,
2324 IrInstructionIdResultPtr,
2325 IrInstructionIdOpaqueType,2330 IrInstructionIdOpaqueType,
2326 IrInstructionIdSetAlignStack,2331 IrInstructionIdSetAlignStack,
2327 IrInstructionIdArgType,2332 IrInstructionIdArgType,
2328 IrInstructionIdExport,2333 IrInstructionIdExport,
2329 IrInstructionIdErrorReturnTrace,2334 IrInstructionIdErrorReturnTrace,
2330 IrInstructionIdErrorUnion,2335 IrInstructionIdErrorUnion,
2331 IrInstructionIdCancel,
2332 IrInstructionIdGetImplicitAllocator,
2333 IrInstructionIdCoroId,
2334 IrInstructionIdCoroAlloc,
2335 IrInstructionIdCoroSize,
2336 IrInstructionIdCoroBegin,
2337 IrInstructionIdCoroAllocFail,
2338 IrInstructionIdCoroSuspend,
2339 IrInstructionIdCoroEnd,
2340 IrInstructionIdCoroFree,
2341 IrInstructionIdCoroResume,
2342 IrInstructionIdCoroSave,
2343 IrInstructionIdCoroPromise,
2344 IrInstructionIdCoroAllocHelper,
2345 IrInstructionIdAtomicRmw,2336 IrInstructionIdAtomicRmw,
2346 IrInstructionIdAtomicLoad,2337 IrInstructionIdAtomicLoad,
2347 IrInstructionIdPromiseResultType,
2348 IrInstructionIdAwaitBookkeeping,
2349 IrInstructionIdSaveErrRetAddr,2338 IrInstructionIdSaveErrRetAddr,
2350 IrInstructionIdAddImplicitReturnType,2339 IrInstructionIdAddImplicitReturnType,
2351 IrInstructionIdMergeErrRetTraces,
2352 IrInstructionIdMarkErrRetTracePtr,
2353 IrInstructionIdErrSetCast,2340 IrInstructionIdErrSetCast,
2354 IrInstructionIdToBytes,2341 IrInstructionIdToBytes,
2355 IrInstructionIdFromBytes,2342 IrInstructionIdFromBytes,
...@@ -2365,6 +2352,13 @@ enum IrInstructionId {...@@ -2365,6 +2352,13 @@ enum IrInstructionId {
2365 IrInstructionIdEndExpr,2352 IrInstructionIdEndExpr,
2366 IrInstructionIdPtrOfArrayToSlice,2353 IrInstructionIdPtrOfArrayToSlice,
2367 IrInstructionIdUnionInitNamedField,2354 IrInstructionIdUnionInitNamedField,
2355 IrInstructionIdSuspendBegin,
2356 IrInstructionIdSuspendFinish,
2357 IrInstructionIdAwaitSrc,
2358 IrInstructionIdAwaitGen,
2359 IrInstructionIdResume,
2360 IrInstructionIdSpillBegin,
2361 IrInstructionIdSpillEnd,
2368};2362};
23692363
2370struct IrInstruction {2364struct IrInstruction {
...@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {...@@ -2607,7 +2601,6 @@ struct IrInstructionCallSrc {
2607 IrInstruction **args;2601 IrInstruction **args;
2608 ResultLoc *result_loc;2602 ResultLoc *result_loc;
26092603
2610 IrInstruction *async_allocator;
2611 IrInstruction *new_stack;2604 IrInstruction *new_stack;
2612 FnInline fn_inline;2605 FnInline fn_inline;
2613 bool is_async;2606 bool is_async;
...@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {...@@ -2622,8 +2615,8 @@ struct IrInstructionCallGen {
2622 size_t arg_count;2615 size_t arg_count;
2623 IrInstruction **args;2616 IrInstruction **args;
2624 IrInstruction *result_loc;2617 IrInstruction *result_loc;
2618 IrInstruction *frame_result_loc;
26252619
2626 IrInstruction *async_allocator;
2627 IrInstruction *new_stack;2620 IrInstruction *new_stack;
2628 FnInline fn_inline;2621 FnInline fn_inline;
2629 bool is_async;2622 bool is_async;
...@@ -2639,7 +2632,7 @@ struct IrInstructionConst {...@@ -2639,7 +2632,7 @@ struct IrInstructionConst {
2639struct IrInstructionReturn {2632struct IrInstructionReturn {
2640 IrInstruction base;2633 IrInstruction base;
26412634
2642 IrInstruction *value;2635 IrInstruction *operand;
2643};2636};
26442637
2645enum CastOp {2638enum CastOp {
...@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {...@@ -2744,7 +2737,7 @@ struct IrInstructionPtrType {
2744 bool is_allow_zero;2737 bool is_allow_zero;
2745};2738};
27462739
2747struct IrInstructionPromiseType {2740struct IrInstructionAnyFrameType {
2748 IrInstruction base;2741 IrInstruction base;
27492742
2750 IrInstruction *payload_type;2743 IrInstruction *payload_type;
...@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {...@@ -3084,8 +3077,26 @@ struct IrInstructionFrameAddress {
3084 IrInstruction base;3077 IrInstruction base;
3085};3078};
30863079
3087struct IrInstructionHandle {3080struct IrInstructionFrameHandle {
3081 IrInstruction base;
3082};
3083
3084struct IrInstructionFrameType {
3085 IrInstruction base;
3086
3087 IrInstruction *fn;
3088};
3089
3090struct IrInstructionFrameSizeSrc {
3091 IrInstruction base;
3092
3093 IrInstruction *fn;
3094};
3095
3096struct IrInstructionFrameSizeGen {
3088 IrInstruction base;3097 IrInstruction base;
3098
3099 IrInstruction *fn;
3089};3100};
30903101
3091enum IrOverflowOp {3102enum IrOverflowOp {
...@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {...@@ -3127,6 +3138,7 @@ struct IrInstructionTestErrSrc {
3127 IrInstruction base;3138 IrInstruction base;
31283139
3129 bool resolve_err_set;3140 bool resolve_err_set;
3141 bool base_ptr_is_payload;
3130 IrInstruction *base_ptr;3142 IrInstruction *base_ptr;
3131};3143};
31323144
...@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {...@@ -3179,7 +3191,6 @@ struct IrInstructionFnProto {
3179 IrInstruction **param_types;3191 IrInstruction **param_types;
3180 IrInstruction *align_value;3192 IrInstruction *align_value;
3181 IrInstruction *return_type;3193 IrInstruction *return_type;
3182 IrInstruction *async_allocator_type_value;
3183 bool is_var_args;3194 bool is_var_args;
3184};3195};
31853196
...@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {...@@ -3409,95 +3420,6 @@ struct IrInstructionErrorUnion {
3409 IrInstruction *payload;3420 IrInstruction *payload;
3410};3421};
34113422
3412struct IrInstructionCancel {
3413 IrInstruction base;
3414
3415 IrInstruction *target;
3416};
3417
3418enum ImplicitAllocatorId {
3419 ImplicitAllocatorIdArg,
3420 ImplicitAllocatorIdLocalVar,
3421};
3422
3423struct IrInstructionGetImplicitAllocator {
3424 IrInstruction base;
3425
3426 ImplicitAllocatorId id;
3427};
3428
3429struct IrInstructionCoroId {
3430 IrInstruction base;
3431
3432 IrInstruction *promise_ptr;
3433};
3434
3435struct IrInstructionCoroAlloc {
3436 IrInstruction base;
3437
3438 IrInstruction *coro_id;
3439};
3440
3441struct IrInstructionCoroSize {
3442 IrInstruction base;
3443};
3444
3445struct IrInstructionCoroBegin {
3446 IrInstruction base;
3447
3448 IrInstruction *coro_id;
3449 IrInstruction *coro_mem_ptr;
3450};
3451
3452struct IrInstructionCoroAllocFail {
3453 IrInstruction base;
3454
3455 IrInstruction *err_val;
3456};
3457
3458struct IrInstructionCoroSuspend {
3459 IrInstruction base;
3460
3461 IrInstruction *save_point;
3462 IrInstruction *is_final;
3463};
3464
3465struct IrInstructionCoroEnd {
3466 IrInstruction base;
3467};
3468
3469struct IrInstructionCoroFree {
3470 IrInstruction base;
3471
3472 IrInstruction *coro_id;
3473 IrInstruction *coro_handle;
3474};
3475
3476struct IrInstructionCoroResume {
3477 IrInstruction base;
3478
3479 IrInstruction *awaiter_handle;
3480};
3481
3482struct IrInstructionCoroSave {
3483 IrInstruction base;
3484
3485 IrInstruction *coro_handle;
3486};
3487
3488struct IrInstructionCoroPromise {
3489 IrInstruction base;
3490
3491 IrInstruction *coro_handle;
3492};
3493
3494struct IrInstructionCoroAllocHelper {
3495 IrInstruction base;
3496
3497 IrInstruction *realloc_fn;
3498 IrInstruction *coro_size;
3499};
3500
3501struct IrInstructionAtomicRmw {3423struct IrInstructionAtomicRmw {
3502 IrInstruction base;3424 IrInstruction base;
35033425
...@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {...@@ -3519,18 +3441,6 @@ struct IrInstructionAtomicLoad {
3519 AtomicOrder resolved_ordering;3441 AtomicOrder resolved_ordering;
3520};3442};
35213443
3522struct IrInstructionPromiseResultType {
3523 IrInstruction base;
3524
3525 IrInstruction *promise_type;
3526};
3527
3528struct IrInstructionAwaitBookkeeping {
3529 IrInstruction base;
3530
3531 IrInstruction *promise_result_type;
3532};
3533
3534struct IrInstructionSaveErrRetAddr {3444struct IrInstructionSaveErrRetAddr {
3535 IrInstruction base;3445 IrInstruction base;
3536};3446};
...@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {...@@ -3541,20 +3451,6 @@ struct IrInstructionAddImplicitReturnType {
3541 IrInstruction *value;3451 IrInstruction *value;
3542};3452};
35433453
3544struct IrInstructionMergeErrRetTraces {
3545 IrInstruction base;
3546
3547 IrInstruction *coro_promise_ptr;
3548 IrInstruction *src_err_ret_trace_ptr;
3549 IrInstruction *dest_err_ret_trace_ptr;
3550};
3551
3552struct IrInstructionMarkErrRetTracePtr {
3553 IrInstruction base;
3554
3555 IrInstruction *err_ret_trace_ptr;
3556};
3557
3558// For float ops which take a single argument3454// For float ops which take a single argument
3559struct IrInstructionFloatOp {3455struct IrInstructionFloatOp {
3560 IrInstruction base;3456 IrInstruction base;
...@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {...@@ -3645,6 +3541,7 @@ struct IrInstructionAllocaGen {
36453541
3646 uint32_t align;3542 uint32_t align;
3647 const char *name_hint;3543 const char *name_hint;
3544 size_t field_index;
3648};3545};
36493546
3650struct IrInstructionEndExpr {3547struct IrInstructionEndExpr {
...@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {...@@ -3692,6 +3589,56 @@ struct IrInstructionPtrOfArrayToSlice {
3692 IrInstruction *result_loc;3589 IrInstruction *result_loc;
3693};3590};
36943591
3592struct IrInstructionSuspendBegin {
3593 IrInstruction base;
3594
3595 LLVMBasicBlockRef resume_bb;
3596};
3597
3598struct IrInstructionSuspendFinish {
3599 IrInstruction base;
3600
3601 IrInstructionSuspendBegin *begin;
3602};
3603
3604struct IrInstructionAwaitSrc {
3605 IrInstruction base;
3606
3607 IrInstruction *frame;
3608 ResultLoc *result_loc;
3609};
3610
3611struct IrInstructionAwaitGen {
3612 IrInstruction base;
3613
3614 IrInstruction *frame;
3615 IrInstruction *result_loc;
3616};
3617
3618struct IrInstructionResume {
3619 IrInstruction base;
3620
3621 IrInstruction *frame;
3622};
3623
3624enum SpillId {
3625 SpillIdInvalid,
3626 SpillIdRetErrCode,
3627};
3628
3629struct IrInstructionSpillBegin {
3630 IrInstruction base;
3631
3632 SpillId spill_id;
3633 IrInstruction *operand;
3634};
3635
3636struct IrInstructionSpillEnd {
3637 IrInstruction base;
3638
3639 IrInstructionSpillBegin *begin;
3640};
3641
3695enum ResultLocId {3642enum ResultLocId {
3696 ResultLocIdInvalid,3643 ResultLocIdInvalid,
3697 ResultLocIdNone,3644 ResultLocIdNone,
...@@ -3772,23 +3719,19 @@ static const size_t slice_len_index = 1;...@@ -3772,23 +3719,19 @@ static const size_t slice_len_index = 1;
3772static const size_t maybe_child_index = 0;3719static const size_t maybe_child_index = 0;
3773static const size_t maybe_null_index = 1;3720static const size_t maybe_null_index = 1;
37743721
3775static const size_t err_union_err_index = 0;3722static const size_t err_union_payload_index = 0;
3776static const size_t err_union_payload_index = 1;3723static const size_t err_union_err_index = 1;
37773724
3778// TODO call graph analysis to find out what this number needs to be for every function3725// label (grep this): [fn_frame_struct_layout]
3779// MUST BE A POWER OF TWO.3726static const size_t frame_fn_ptr_index = 0;
3780static const size_t stack_trace_ptr_count = 32;3727static const size_t frame_resume_index = 1;
3728static const size_t frame_awaiter_index = 2;
3729static const size_t frame_ret_start = 3;
37813730
3782// these belong to the async function3731// TODO https://github.com/ziglang/zig/issues/3056
3783#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"3732// We require this to be a power of 2 so that we can use shifting rather than
3784#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"3733// remainder division.
3785#define RESULT_FIELD_NAME "result"3734static const size_t stack_trace_ptr_count = 32; // Must be a power of 2.
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"
37923735
3793#define NAMESPACE_SEP_CHAR '.'3736#define NAMESPACE_SEP_CHAR '.'
3794#define NAMESPACE_SEP_STR "."3737#define NAMESPACE_SEP_STR "."
...@@ -3811,11 +3754,13 @@ enum FnWalkId {...@@ -3811,11 +3754,13 @@ enum FnWalkId {
38113754
3812struct FnWalkAttrs {3755struct FnWalkAttrs {
3813 ZigFn *fn;3756 ZigFn *fn;
3757 LLVMValueRef llvm_fn;
3814 unsigned gen_i;3758 unsigned gen_i;
3815};3759};
38163760
3817struct FnWalkCall {3761struct FnWalkCall {
3818 ZigList<LLVMValueRef> *gen_param_values;3762 ZigList<LLVMValueRef> *gen_param_values;
3763 ZigList<ZigType *> *gen_param_types;
3819 IrInstructionCallGen *inst;3764 IrInstructionCallGen *inst;
3820 bool is_var_args;3765 bool is_var_args;
3821};3766};
src/analyze.cpp+882-244
...@@ -7,6 +7,7 @@...@@ -7,6 +7,7 @@
77
8#include "analyze.hpp"8#include "analyze.hpp"
9#include "ast_render.hpp"9#include "ast_render.hpp"
10#include "codegen.hpp"
10#include "config.h"11#include "config.h"
11#include "error.hpp"12#include "error.hpp"
12#include "ir.hpp"13#include "ir.hpp"
...@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -31,6 +32,11 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
31static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);32static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, ScopeDecls *dest_decls_scope);
32static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);33static void resolve_use_decl(CodeGen *g, TldUsingNamespace *tld_using_namespace, ScopeDecls *dest_decls_scope);
3334
35// nullptr means not analyzed yet; this one means currently being analyzed
36static const AstNode *inferred_async_checking = reinterpret_cast<AstNode *>(0x1);
37// this one means analyzed and it's not async
38static const AstNode *inferred_async_none = reinterpret_cast<AstNode *>(0x2);
39
34static bool is_top_level_struct(ZigType *import) {40static bool is_top_level_struct(ZigType *import) {
35 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;41 return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr;
36}42}
...@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {...@@ -56,14 +62,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
56 return err;62 return err;
57}63}
5864
59ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {65ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
60 Token fake_token;66 Token fake_token;
61 fake_token.start_line = node->line;67 fake_token.start_line = node->line;
62 fake_token.start_column = node->column;68 fake_token.start_column = node->column;
63 return add_token_error(g, node->owner, &fake_token, msg);69 return add_token_error(g, node->owner, &fake_token, msg);
64}70}
6571
66ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {72ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) {
67 Token fake_token;73 Token fake_token;
68 fake_token.start_line = node->line;74 fake_token.start_line = node->line;
69 fake_token.start_column = node->column;75 fake_token.start_column = node->column;
...@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {...@@ -188,12 +194,6 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
188 return &scope->base;194 return &scope->base;
189}195}
190196
191Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent) {
192 ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1);
193 init_scope(g, &scope->base, ScopeIdCoroPrelude, node, parent);
194 return &scope->base;
195}
196
197ZigType *get_scope_import(Scope *scope) {197ZigType *get_scope_import(Scope *scope) {
198 while (scope) {198 while (scope) {
199 if (scope->id == ScopeIdDecls) {199 if (scope->id == ScopeIdDecls) {
...@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {...@@ -234,6 +234,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
234 return type_entry->data.enumeration.decl_node;234 return type_entry->data.enumeration.decl_node;
235 case ZigTypeIdUnion:235 case ZigTypeIdUnion:
236 return type_entry->data.unionation.decl_node;236 return type_entry->data.unionation.decl_node;
237 case ZigTypeIdFnFrame:
238 return type_entry->data.frame.fn->proto_node;
237 case ZigTypeIdOpaque:239 case ZigTypeIdOpaque:
238 case ZigTypeIdMetaType:240 case ZigTypeIdMetaType:
239 case ZigTypeIdVoid:241 case ZigTypeIdVoid:
...@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {...@@ -254,8 +256,8 @@ AstNode *type_decl_node(ZigType *type_entry) {
254 case ZigTypeIdFn:256 case ZigTypeIdFn:
255 case ZigTypeIdBoundFn:257 case ZigTypeIdBoundFn:
256 case ZigTypeIdArgTuple:258 case ZigTypeIdArgTuple:
257 case ZigTypeIdPromise:
258 case ZigTypeIdVector:259 case ZigTypeIdVector:
260 case ZigTypeIdAnyFrame:
259 return nullptr;261 return nullptr;
260 }262 }
261 zig_unreachable();263 zig_unreachable();
...@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {...@@ -269,6 +271,20 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
269 return type_entry->data.structure.resolve_status >= status;271 return type_entry->data.structure.resolve_status >= status;
270 case ZigTypeIdUnion:272 case ZigTypeIdUnion:
271 return type_entry->data.unionation.resolve_status >= status;273 return type_entry->data.unionation.resolve_status >= status;
274 case ZigTypeIdFnFrame:
275 switch (status) {
276 case ResolveStatusInvalid:
277 zig_unreachable();
278 case ResolveStatusUnstarted:
279 case ResolveStatusZeroBitsKnown:
280 return true;
281 case ResolveStatusAlignmentKnown:
282 case ResolveStatusSizeKnown:
283 return type_entry->data.frame.locals_struct != nullptr;
284 case ResolveStatusLLVMFwdDecl:
285 case ResolveStatusLLVMFull:
286 return type_entry->llvm_type != nullptr;
287 }
272 case ZigTypeIdEnum:288 case ZigTypeIdEnum:
273 switch (status) {289 switch (status) {
274 case ResolveStatusUnstarted:290 case ResolveStatusUnstarted:
...@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {...@@ -307,8 +323,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
307 case ZigTypeIdFn:323 case ZigTypeIdFn:
308 case ZigTypeIdBoundFn:324 case ZigTypeIdBoundFn:
309 case ZigTypeIdArgTuple:325 case ZigTypeIdArgTuple:
310 case ZigTypeIdPromise:
311 case ZigTypeIdVector:326 case ZigTypeIdVector:
327 case ZigTypeIdAnyFrame:
312 return true;328 return true;
313 }329 }
314 zig_unreachable();330 zig_unreachable();
...@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {...@@ -341,27 +357,27 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
341 return get_int_type(g, false, bits_needed_for_unsigned(x));357 return get_int_type(g, false, bits_needed_for_unsigned(x));
342}358}
343359
344ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {360ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) {
345 if (result_type != nullptr && result_type->promise_parent != nullptr) {361 if (result_type != nullptr && result_type->any_frame_parent != nullptr) {
346 return result_type->promise_parent;362 return result_type->any_frame_parent;
347 } else if (result_type == nullptr && g->builtin_types.entry_promise != nullptr) {363 } else if (result_type == nullptr && g->builtin_types.entry_any_frame != nullptr) {
348 return g->builtin_types.entry_promise;364 return g->builtin_types.entry_any_frame;
349 }365 }
350366
351 ZigType *entry = new_type_table_entry(ZigTypeIdPromise);367 ZigType *entry = new_type_table_entry(ZigTypeIdAnyFrame);
352 entry->abi_size = g->builtin_types.entry_usize->abi_size;368 entry->abi_size = g->builtin_types.entry_usize->abi_size;
353 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;369 entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits;
354 entry->abi_align = g->builtin_types.entry_usize->abi_align;370 entry->abi_align = g->builtin_types.entry_usize->abi_align;
355 entry->data.promise.result_type = result_type;371 entry->data.any_frame.result_type = result_type;
356 buf_init_from_str(&entry->name, "promise");372 buf_init_from_str(&entry->name, "anyframe");
357 if (result_type != nullptr) {373 if (result_type != nullptr) {
358 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));374 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
359 }375 }
360376
361 if (result_type != nullptr) {377 if (result_type != nullptr) {
362 result_type->promise_parent = entry;378 result_type->any_frame_parent = entry;
363 } else if (result_type == nullptr) {379 } else if (result_type == nullptr) {
364 g->builtin_types.entry_promise = entry;380 g->builtin_types.entry_any_frame = entry;
365 }381 }
366 return entry;382 return entry;
367}383}
...@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {...@@ -378,6 +394,25 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
378 zig_unreachable();394 zig_unreachable();
379}395}
380396
397ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
398 if (fn->frame_type != nullptr) {
399 return fn->frame_type;
400 }
401
402 ZigType *entry = new_type_table_entry(ZigTypeIdFnFrame);
403 buf_resize(&entry->name, 0);
404 buf_appendf(&entry->name, "@Frame(%s)", buf_ptr(&fn->symbol_name));
405
406 entry->data.frame.fn = fn;
407
408 // Async function frames are always non-zero bits because they always have a resume index.
409 entry->abi_size = SIZE_MAX;
410 entry->size_in_bits = SIZE_MAX;
411
412 fn->frame_type = entry;
413 return entry;
414}
415
381ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,416ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
382 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,417 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
383 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)418 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
...@@ -490,42 +525,6 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {...@@ -490,42 +525,6 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
490 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);525 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
491}526}
492527
493ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
494 if (return_type->promise_frame_parent != nullptr) {
495 return return_type->promise_frame_parent;
496 }
497
498 ZigType *atomic_state_type = g->builtin_types.entry_usize;
499 ZigType *result_ptr_type = get_pointer_to_type(g, return_type, false);
500
501 ZigList<const char *> field_names = {};
502 field_names.append(ATOMIC_STATE_FIELD_NAME);
503 field_names.append(RESULT_FIELD_NAME);
504 field_names.append(RESULT_PTR_FIELD_NAME);
505 if (g->have_err_ret_tracing) {
506 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
507 field_names.append(ERR_RET_TRACE_FIELD_NAME);
508 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
509 }
510
511 ZigList<ZigType *> field_types = {};
512 field_types.append(atomic_state_type);
513 field_types.append(return_type);
514 field_types.append(result_ptr_type);
515 if (g->have_err_ret_tracing) {
516 field_types.append(get_ptr_to_stack_trace_type(g));
517 field_types.append(g->stack_trace_type);
518 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
519 }
520
521 assert(field_names.length == field_types.length);
522 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
523 ZigType *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
524
525 return_type->promise_frame_parent = entry;
526 return entry;
527}
528
529ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {528ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
530 if (child_type->optional_parent != nullptr) {529 if (child_type->optional_parent != nullptr) {
531 return child_type->optional_parent;530 return child_type->optional_parent;
...@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa...@@ -631,6 +630,7 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
631 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);630 size_t field2_offset = next_field_offset(0, entry->abi_align, field_sizes[0], field_aligns[1]);
632 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);631 entry->abi_size = next_field_offset(field2_offset, entry->abi_align, field_sizes[1], entry->abi_align);
633 entry->size_in_bits = entry->abi_size * 8;632 entry->size_in_bits = entry->abi_size * 8;
633 entry->data.error_union.pad_bytes = entry->abi_size - (field2_offset + field_sizes[1]);
634 }634 }
635635
636 g->type_table.put(type_id, entry);636 g->type_table.put(type_id, entry);
...@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {...@@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
828 zig_unreachable();828 zig_unreachable();
829}829}
830830
831ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {831ZigType *get_stack_trace_type(CodeGen *g) {
832 if (g->stack_trace_type == nullptr) {832 if (g->stack_trace_type == nullptr) {
833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");833 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);834 assert(stack_trace_type_val->type->id == ZigTypeIdMetaType);
835835
836 g->stack_trace_type = stack_trace_type_val->data.x_type;836 g->stack_trace_type = stack_trace_type_val->data.x_type;
837 assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));837 assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown));
838
839 g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false);
840 }838 }
841 return g->ptr_to_stack_trace_type;839 return g->stack_trace_type;
842}840}
843841
844bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {842bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
...@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -879,13 +877,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
879877
880 // populate the name of the type878 // populate the name of the type
881 buf_resize(&fn_type->name, 0);879 buf_resize(&fn_type->name, 0);
882 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {880 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
883 assert(fn_type_id->async_allocator_type != nullptr);881 buf_appendf(&fn_type->name, "%s", cc_str);
884 buf_appendf(&fn_type->name, "async<%s> ", buf_ptr(&fn_type_id->async_allocator_type->name));
885 } else {
886 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
887 buf_appendf(&fn_type->name, "%s", cc_str);
888 }
889 buf_appendf(&fn_type->name, "fn(");882 buf_appendf(&fn_type->name, "fn(");
890 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {883 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
891 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];884 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
...@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {...@@ -998,14 +991,8 @@ ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
998ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {991ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
999 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);992 ZigType *fn_type = new_type_table_entry(ZigTypeIdFn);
1000 buf_resize(&fn_type->name, 0);993 buf_resize(&fn_type->name, 0);
1001 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {994 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1002 const char *async_allocator_type_str = (fn_type->data.fn.fn_type_id.async_allocator_type == nullptr) ?995 buf_appendf(&fn_type->name, "%s", cc_str);
1003 "var" : buf_ptr(&fn_type_id->async_allocator_type->name);
1004 buf_appendf(&fn_type->name, "async(%s) ", async_allocator_type_str);
1005 } else {
1006 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1007 buf_appendf(&fn_type->name, "%s", cc_str);
1008 }
1009 buf_appendf(&fn_type->name, "fn(");996 buf_appendf(&fn_type->name, "fn(");
1010 size_t i = 0;997 size_t i = 0;
1011 for (; i < fn_type_id->next_param_index; i += 1) {998 for (; i < fn_type_id->next_param_index; i += 1) {
...@@ -1119,7 +1106,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType...@@ -1119,7 +1106,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
1119 case ZigTypeIdBoundFn:1106 case ZigTypeIdBoundFn:
1120 case ZigTypeIdArgTuple:1107 case ZigTypeIdArgTuple:
1121 case ZigTypeIdOpaque:1108 case ZigTypeIdOpaque:
1122 case ZigTypeIdPromise:1109 case ZigTypeIdFnFrame:
1110 case ZigTypeIdAnyFrame:
1123 add_node_error(g, source_node,1111 add_node_error(g, source_node,
1124 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",1112 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
1125 buf_ptr(&type_entry->name)));1113 buf_ptr(&type_entry->name)));
...@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {...@@ -1207,8 +1195,9 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
1207 case ZigTypeIdErrorSet:1195 case ZigTypeIdErrorSet:
1208 case ZigTypeIdBoundFn:1196 case ZigTypeIdBoundFn:
1209 case ZigTypeIdArgTuple:1197 case ZigTypeIdArgTuple:
1210 case ZigTypeIdPromise:
1211 case ZigTypeIdVoid:1198 case ZigTypeIdVoid:
1199 case ZigTypeIdFnFrame:
1200 case ZigTypeIdAnyFrame:
1212 return false;1201 return false;
1213 case ZigTypeIdOpaque:1202 case ZigTypeIdOpaque:
1214 case ZigTypeIdUnreachable:1203 case ZigTypeIdUnreachable:
...@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1378,8 +1367,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1378 case ZigTypeIdEnum:1367 case ZigTypeIdEnum:
1379 case ZigTypeIdUnion:1368 case ZigTypeIdUnion:
1380 case ZigTypeIdFn:1369 case ZigTypeIdFn:
1381 case ZigTypeIdPromise:
1382 case ZigTypeIdVector:1370 case ZigTypeIdVector:
1371 case ZigTypeIdFnFrame:
1372 case ZigTypeIdAnyFrame:
1383 switch (type_requires_comptime(g, type_entry)) {1373 switch (type_requires_comptime(g, type_entry)) {
1384 case ReqCompTimeNo:1374 case ReqCompTimeNo:
1385 break;1375 break;
...@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1474,8 +1464,9 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1474 case ZigTypeIdEnum:1464 case ZigTypeIdEnum:
1475 case ZigTypeIdUnion:1465 case ZigTypeIdUnion:
1476 case ZigTypeIdFn:1466 case ZigTypeIdFn:
1477 case ZigTypeIdPromise:
1478 case ZigTypeIdVector:1467 case ZigTypeIdVector:
1468 case ZigTypeIdFnFrame:
1469 case ZigTypeIdAnyFrame:
1479 switch (type_requires_comptime(g, fn_type_id.return_type)) {1470 switch (type_requires_comptime(g, fn_type_id.return_type)) {
1480 case ReqCompTimeInvalid:1471 case ReqCompTimeInvalid:
1481 return g->builtin_types.entry_invalid;1472 return g->builtin_types.entry_invalid;
...@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1487,16 +1478,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1487 break;1478 break;
1488 }1479 }
14891480
1490 if (fn_type_id.cc == CallingConventionAsync) {
1491 if (fn_proto->async_allocator_type == nullptr) {
1492 return get_generic_fn_type(g, &fn_type_id);
1493 }
1494 fn_type_id.async_allocator_type = analyze_type_expr(g, child_scope, fn_proto->async_allocator_type);
1495 if (type_is_invalid(fn_type_id.async_allocator_type)) {
1496 return g->builtin_types.entry_invalid;
1497 }
1498 }
1499
1500 return get_fn_type(g, &fn_type_id);1481 return get_fn_type(g, &fn_type_id);
1501}1482}
15021483
...@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {...@@ -1516,9 +1497,14 @@ bool type_is_invalid(ZigType *type_entry) {
1516 zig_unreachable();1497 zig_unreachable();
1517}1498}
15181499
1500struct SrcField {
1501 const char *name;
1502 ZigType *ty;
1503 unsigned align;
1504};
15191505
1520ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],1506static ZigType *get_struct_type(CodeGen *g, const char *type_name, SrcField fields[], size_t field_count,
1521 ZigType *field_types[], size_t field_count)1507 unsigned min_abi_align)
1522{1508{
1523 ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);1509 ZigType *struct_type = new_type_table_entry(ZigTypeIdStruct);
15241510
...@@ -1530,22 +1516,20 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na...@@ -1530,22 +1516,20 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
1530 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);1516 struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
1531 struct_type->data.structure.fields_by_name.init(field_count);1517 struct_type->data.structure.fields_by_name.init(field_count);
15321518
1533 size_t abi_align = 0;1519 size_t abi_align = min_abi_align;
1534 for (size_t i = 0; i < field_count; i += 1) {1520 for (size_t i = 0; i < field_count; i += 1) {
1535 TypeStructField *field = &struct_type->data.structure.fields[i];1521 TypeStructField *field = &struct_type->data.structure.fields[i];
1536 field->name = buf_create_from_str(field_names[i]);1522 field->name = buf_create_from_str(fields[i].name);
1537 field->type_entry = field_types[i];1523 field->type_entry = fields[i].ty;
1538 field->src_index = i;1524 field->src_index = i;
1525 field->align = fields[i].align;
15391526
1540 if (type_has_bits(field->type_entry)) {1527 if (type_has_bits(field->type_entry)) {
1541 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));1528 assert(type_is_resolved(field->type_entry, ResolveStatusSizeKnown));
1542 if (field->type_entry->abi_align > abi_align) {1529 unsigned field_abi_align = max(field->align, field->type_entry->abi_align);
1543 abi_align = field->type_entry->abi_align;1530 if (field_abi_align > abi_align) {
1531 abi_align = field_abi_align;
1544 }1532 }
1545 field->gen_index = struct_type->data.structure.gen_field_count;
1546 struct_type->data.structure.gen_field_count += 1;
1547 } else {
1548 field->gen_index = SIZE_MAX;
1549 }1533 }
15501534
1551 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);1535 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
...@@ -1555,17 +1539,24 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na...@@ -1555,17 +1539,24 @@ ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_na
1555 size_t next_offset = 0;1539 size_t next_offset = 0;
1556 for (size_t i = 0; i < field_count; i += 1) {1540 for (size_t i = 0; i < field_count; i += 1) {
1557 TypeStructField *field = &struct_type->data.structure.fields[i];1541 TypeStructField *field = &struct_type->data.structure.fields[i];
1558 if (field->gen_index == SIZE_MAX)1542 if (!type_has_bits(field->type_entry))
1559 continue;1543 continue;
1544
1560 field->offset = next_offset;1545 field->offset = next_offset;
1546
1547 // find the next non-zero-byte field for offset calculations
1561 size_t next_src_field_index = i + 1;1548 size_t next_src_field_index = i + 1;
1562 for (; next_src_field_index < field_count; next_src_field_index += 1) {1549 for (; next_src_field_index < field_count; next_src_field_index += 1) {
1563 if (struct_type->data.structure.fields[next_src_field_index].gen_index != SIZE_MAX) {1550 if (type_has_bits(struct_type->data.structure.fields[next_src_field_index].type_entry))
1564 break;1551 break;
1565 }
1566 }1552 }
1567 size_t next_abi_align = (next_src_field_index == field_count) ?1553 size_t next_abi_align;
1568 abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align;1554 if (next_src_field_index == field_count) {
1555 next_abi_align = abi_align;
1556 } else {
1557 next_abi_align = max(fields[next_src_field_index].align,
1558 struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align);
1559 }
1569 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);1560 next_offset = next_field_offset(next_offset, abi_align, field->type_entry->abi_size, next_abi_align);
1570 }1561 }
15711562
...@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {...@@ -2653,7 +2644,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26532644
2654 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;2645 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26552646
2656 fn_entry->codegen = g;
2657 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;2647 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
2658 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;2648 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
2659 fn_entry->analyzed_executable.fn_entry = fn_entry;2649 fn_entry->analyzed_executable.fn_entry = fn_entry;
...@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2781,6 +2771,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2781 }2771 }
2782 }2772 }
2783 } else {2773 } else {
2774 fn_table_entry->inferred_async_node = inferred_async_none;
2784 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);2775 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
2785 }2776 }
27862777
...@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2802,6 +2793,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2802 g->fn_defs.append(fn_table_entry);2793 g->fn_defs.append(fn_table_entry);
2803 }2794 }
28042795
2796 // if the calling convention implies that it cannot be async, we save that for later
2797 // and leave the value to be nullptr to indicate that we have not emitted possible
2798 // compile errors for improperly calling async functions.
2799 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
2800 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
2801 }
2802
2805 if (scope_is_root_decls(tld_fn->base.parent_scope) &&2803 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
2806 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))2804 (import == g->root_import || import->data.structure.root_struct->package == g->panic_package))
2807 {2805 {
...@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3035,12 +3033,11 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3035 case NodeTypeIfErrorExpr:3033 case NodeTypeIfErrorExpr:
3036 case NodeTypeIfOptional:3034 case NodeTypeIfOptional:
3037 case NodeTypeErrorSetDecl:3035 case NodeTypeErrorSetDecl:
3038 case NodeTypeCancel:
3039 case NodeTypeResume:3036 case NodeTypeResume:
3040 case NodeTypeAwaitExpr:3037 case NodeTypeAwaitExpr:
3041 case NodeTypeSuspend:3038 case NodeTypeSuspend:
3042 case NodeTypePromiseType:
3043 case NodeTypeEnumLiteral:3039 case NodeTypeEnumLiteral:
3040 case NodeTypeAnyFrameType:
3044 zig_unreachable();3041 zig_unreachable();
3045 }3042 }
3046}3043}
...@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry...@@ -3091,8 +3088,9 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
3091 case ZigTypeIdUnion:3088 case ZigTypeIdUnion:
3092 case ZigTypeIdFn:3089 case ZigTypeIdFn:
3093 case ZigTypeIdBoundFn:3090 case ZigTypeIdBoundFn:
3094 case ZigTypeIdPromise:
3095 case ZigTypeIdVector:3091 case ZigTypeIdVector:
3092 case ZigTypeIdFnFrame:
3093 case ZigTypeIdAnyFrame:
3096 return type_entry;3094 return type_entry;
3097 }3095 }
3098 zig_unreachable();3096 zig_unreachable();
...@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {...@@ -3592,8 +3590,9 @@ bool is_container(ZigType *type_entry) {
3592 case ZigTypeIdBoundFn:3590 case ZigTypeIdBoundFn:
3593 case ZigTypeIdArgTuple:3591 case ZigTypeIdArgTuple:
3594 case ZigTypeIdOpaque:3592 case ZigTypeIdOpaque:
3595 case ZigTypeIdPromise:
3596 case ZigTypeIdVector:3593 case ZigTypeIdVector:
3594 case ZigTypeIdFnFrame:
3595 case ZigTypeIdAnyFrame:
3597 return false;3596 return false;
3598 }3597 }
3599 zig_unreachable();3598 zig_unreachable();
...@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {...@@ -3649,8 +3648,9 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
3649 case ZigTypeIdInvalid:3648 case ZigTypeIdInvalid:
3650 case ZigTypeIdArgTuple:3649 case ZigTypeIdArgTuple:
3651 case ZigTypeIdOpaque:3650 case ZigTypeIdOpaque:
3652 case ZigTypeIdPromise:
3653 case ZigTypeIdVector:3651 case ZigTypeIdVector:
3652 case ZigTypeIdFnFrame:
3653 case ZigTypeIdAnyFrame:
3654 zig_unreachable();3654 zig_unreachable();
3655 }3655 }
3656 zig_unreachable();3656 zig_unreachable();
...@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {...@@ -3659,13 +3659,13 @@ Error resolve_container_type(CodeGen *g, ZigType *type_entry) {
3659ZigType *get_src_ptr_type(ZigType *type) {3659ZigType *get_src_ptr_type(ZigType *type) {
3660 if (type->id == ZigTypeIdPointer) return type;3660 if (type->id == ZigTypeIdPointer) return type;
3661 if (type->id == ZigTypeIdFn) return type;3661 if (type->id == ZigTypeIdFn) return type;
3662 if (type->id == ZigTypeIdPromise) return type;3662 if (type->id == ZigTypeIdAnyFrame) return type;
3663 if (type->id == ZigTypeIdOptional) {3663 if (type->id == ZigTypeIdOptional) {
3664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {3664 if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
3665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;3665 return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
3666 }3666 }
3667 if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;3667 if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
3668 if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;3668 if (type->data.maybe.child_type->id == ZigTypeIdAnyFrame) return type->data.maybe.child_type;
3669 }3669 }
3670 return nullptr;3670 return nullptr;
3671}3671}
...@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {...@@ -3681,6 +3681,13 @@ bool type_is_nonnull_ptr(ZigType *type) {
3681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);3681 return get_codegen_ptr_type(type) == type && !ptr_allows_addr_zero(type);
3682}3682}
36833683
3684static uint32_t get_async_frame_align_bytes(CodeGen *g) {
3685 uint32_t a = g->pointer_size_bytes * 2;
3686 // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
3687 if (a < 8) a = 8;
3688 return a;
3689}
3690
3684uint32_t get_ptr_align(CodeGen *g, ZigType *type) {3691uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
3685 ZigType *ptr_type = get_src_ptr_type(type);3692 ZigType *ptr_type = get_src_ptr_type(type);
3686 if (ptr_type->id == ZigTypeIdPointer) {3693 if (ptr_type->id == ZigTypeIdPointer) {
...@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {...@@ -3692,8 +3699,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
3692 // when getting the alignment of `?extern fn() void`.3699 // when getting the alignment of `?extern fn() void`.
3693 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html3700 // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html
3694 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;3701 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
3695 } else if (ptr_type->id == ZigTypeIdPromise) {3702 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3696 return get_coro_frame_align_bytes(g);3703 return get_async_frame_align_bytes(g);
3697 } else {3704 } else {
3698 zig_unreachable();3705 zig_unreachable();
3699 }3706 }
...@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {...@@ -3705,7 +3712,7 @@ bool get_ptr_const(ZigType *type) {
3705 return ptr_type->data.pointer.is_const;3712 return ptr_type->data.pointer.is_const;
3706 } else if (ptr_type->id == ZigTypeIdFn) {3713 } else if (ptr_type->id == ZigTypeIdFn) {
3707 return true;3714 return true;
3708 } else if (ptr_type->id == ZigTypeIdPromise) {3715 } else if (ptr_type->id == ZigTypeIdAnyFrame) {
3709 return true;3716 return true;
3710 } else {3717 } else {
3711 zig_unreachable();3718 zig_unreachable();
...@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour...@@ -3780,18 +3787,128 @@ bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *sour
3780 return true;3787 return true;
3781}3788}
37823789
3783void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {3790static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) {
3784 ZigType *fn_type = fn_table_entry->type_entry;3791 ZigType *frame_type = get_fn_frame_type(g, fn);
3792 Error err;
3793 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {
3794 fn->anal_state = FnAnalStateInvalid;
3795 return;
3796 }
3797}
3798
3799bool fn_is_async(ZigFn *fn) {
3800 assert(fn->inferred_async_node != nullptr);
3801 assert(fn->inferred_async_node != inferred_async_checking);
3802 return fn->inferred_async_node != inferred_async_none;
3803}
3804
3805static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3806 assert(fn->inferred_async_node != nullptr);
3807 assert(fn->inferred_async_node != inferred_async_checking);
3808 assert(fn->inferred_async_node != inferred_async_none);
3809 if (fn->inferred_async_fn != nullptr) {
3810 ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node,
3811 buf_sprintf("async function call here"));
3812 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);
3813 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {
3814 add_error_note(g, msg, fn->inferred_async_node,
3815 buf_sprintf("async calling convention here"));
3816 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {
3817 add_error_note(g, msg, fn->inferred_async_node,
3818 buf_sprintf("suspends here"));
3819 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3820 add_error_note(g, msg, fn->inferred_async_node,
3821 buf_sprintf("await is a suspend point"));
3822 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&
3823 fn->inferred_async_node->data.fn_call_expr.is_builtin)
3824 {
3825 add_error_note(g, msg, fn->inferred_async_node,
3826 buf_sprintf("@frame() causes function to be async"));
3827 } else {
3828 add_error_note(g, msg, fn->inferred_async_node,
3829 buf_sprintf("suspends here"));
3830 }
3831}
3832
3833// This function resolves functions being inferred async.
3834static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
3835 if (fn->inferred_async_node == inferred_async_checking) {
3836 // TODO call graph cycle detected, disallow the recursion
3837 fn->inferred_async_node = inferred_async_none;
3838 return;
3839 }
3840 if (fn->inferred_async_node == inferred_async_none) {
3841 return;
3842 }
3843 if (fn->inferred_async_node != nullptr) {
3844 if (resolve_frame) {
3845 resolve_async_fn_frame(g, fn);
3846 }
3847 return;
3848 }
3849 fn->inferred_async_node = inferred_async_checking;
3850
3851 bool must_not_be_async = false;
3852 if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) {
3853 must_not_be_async = true;
3854 fn->inferred_async_node = inferred_async_none;
3855 }
3856
3857 for (size_t i = 0; i < fn->call_list.length; i += 1) {
3858 IrInstructionCallGen *call = fn->call_list.at(i);
3859 ZigFn *callee = call->fn_entry;
3860 if (callee == nullptr) {
3861 // TODO function pointer call here, could be anything
3862 continue;
3863 }
3864
3865 if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
3866 continue;
3867 if (callee->anal_state == FnAnalStateReady) {
3868 analyze_fn_body(g, callee);
3869 if (callee->anal_state == FnAnalStateInvalid) {
3870 fn->anal_state = FnAnalStateInvalid;
3871 return;
3872 }
3873 }
3874 assert(callee->anal_state == FnAnalStateComplete);
3875 analyze_fn_async(g, callee, true);
3876 if (callee->anal_state == FnAnalStateInvalid) {
3877 fn->anal_state = FnAnalStateInvalid;
3878 return;
3879 }
3880 if (fn_is_async(callee)) {
3881 fn->inferred_async_node = call->base.source_node;
3882 fn->inferred_async_fn = callee;
3883 if (must_not_be_async) {
3884 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3885 buf_sprintf("function with calling convention '%s' cannot be async",
3886 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
3887 add_async_error_notes(g, msg, fn);
3888 fn->anal_state = FnAnalStateInvalid;
3889 return;
3890 }
3891 if (resolve_frame) {
3892 resolve_async_fn_frame(g, fn);
3893 }
3894 return;
3895 }
3896 }
3897 fn->inferred_async_node = inferred_async_none;
3898}
3899
3900static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
3901 ZigType *fn_type = fn->type_entry;
3785 assert(!fn_type->data.fn.is_generic);3902 assert(!fn_type->data.fn.is_generic);
3786 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;3903 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
37873904
3788 ZigType *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,3905 ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,
3789 &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);3906 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
3790 fn_table_entry->src_implicit_return_type = block_return_type;3907 fn->src_implicit_return_type = block_return_type;
37913908
3792 if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {3909 if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) {
3793 assert(g->errors.length > 0);3910 assert(g->errors.length > 0);
3794 fn_table_entry->anal_state = FnAnalStateInvalid;3911 fn->anal_state = FnAnalStateInvalid;
3795 return;3912 return;
3796 }3913 }
37973914
...@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)...@@ -3799,20 +3916,20 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
3799 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;3916 ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
3800 if (return_err_set_type->data.error_set.infer_fn != nullptr) {3917 if (return_err_set_type->data.error_set.infer_fn != nullptr) {
3801 ZigType *inferred_err_set_type;3918 ZigType *inferred_err_set_type;
3802 if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorSet) {3919 if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
3803 inferred_err_set_type = fn_table_entry->src_implicit_return_type;3920 inferred_err_set_type = fn->src_implicit_return_type;
3804 } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {3921 } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
3805 inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;3922 inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
3806 } else {3923 } else {
3807 add_node_error(g, return_type_node,3924 add_node_error(g, return_type_node,
3808 buf_sprintf("function with inferred error set must return at least one possible error"));3925 buf_sprintf("function with inferred error set must return at least one possible error"));
3809 fn_table_entry->anal_state = FnAnalStateInvalid;3926 fn->anal_state = FnAnalStateInvalid;
3810 return;3927 return;
3811 }3928 }
38123929
3813 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {3930 if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
3814 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {3931 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
3815 fn_table_entry->anal_state = FnAnalStateInvalid;3932 fn->anal_state = FnAnalStateInvalid;
3816 return;3933 return;
3817 }3934 }
3818 }3935 }
...@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)...@@ -3832,13 +3949,25 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
3832 }3949 }
3833 }3950 }
38343951
3952 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
3953 if (cc != CallingConventionUnspecified && cc != CallingConventionAsync &&
3954 fn->inferred_async_node != nullptr &&
3955 fn->inferred_async_node != inferred_async_checking &&
3956 fn->inferred_async_node != inferred_async_none)
3957 {
3958 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3959 buf_sprintf("function with calling convention '%s' cannot be async",
3960 calling_convention_name(cc)));
3961 add_async_error_notes(g, msg, fn);
3962 fn->anal_state = FnAnalStateInvalid;
3963 }
3964
3835 if (g->verbose_ir) {3965 if (g->verbose_ir) {
3836 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));3966 fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
3837 ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);3967 ir_print(g, stderr, &fn->analyzed_executable, 4);
3838 fprintf(stderr, "}\n");3968 fprintf(stderr, "}\n");
3839 }3969 }
38403970 fn->anal_state = FnAnalStateComplete;
3841 fn_table_entry->anal_state = FnAnalStateComplete;
3842}3971}
38433972
3844static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {3973static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
...@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {...@@ -4008,6 +4137,16 @@ void semantic_analyze(CodeGen *g) {
4008 analyze_fn_body(g, fn_entry);4137 analyze_fn_body(g, fn_entry);
4009 }4138 }
4010 }4139 }
4140
4141 if (g->errors.length != 0) {
4142 return;
4143 }
4144
4145 // second pass over functions for detecting async
4146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
4147 ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);
4148 analyze_fn_async(g, fn_entry, true);
4149 }
4011}4150}
40124151
4013ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {4152ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
...@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {...@@ -4103,11 +4242,12 @@ bool handle_is_ptr(ZigType *type_entry) {
4103 case ZigTypeIdErrorSet:4242 case ZigTypeIdErrorSet:
4104 case ZigTypeIdFn:4243 case ZigTypeIdFn:
4105 case ZigTypeIdEnum:4244 case ZigTypeIdEnum:
4106 case ZigTypeIdPromise:
4107 case ZigTypeIdVector:4245 case ZigTypeIdVector:
4246 case ZigTypeIdAnyFrame:
4108 return false;4247 return false;
4109 case ZigTypeIdArray:4248 case ZigTypeIdArray:
4110 case ZigTypeIdStruct:4249 case ZigTypeIdStruct:
4250 case ZigTypeIdFnFrame:
4111 return type_has_bits(type_entry);4251 return type_has_bits(type_entry);
4112 case ZigTypeIdErrorUnion:4252 case ZigTypeIdErrorUnion:
4113 return type_has_bits(type_entry->data.error_union.payload_type);4253 return type_has_bits(type_entry->data.error_union.payload_type);
...@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {...@@ -4143,7 +4283,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
4143 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;4283 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
4144 result += id->is_var_args ? (uint32_t)1931444534 : 0;4284 result += id->is_var_args ? (uint32_t)1931444534 : 0;
4145 result += hash_ptr(id->return_type);4285 result += hash_ptr(id->return_type);
4146 result += hash_ptr(id->async_allocator_type);
4147 result += id->alignment * 0xd3b3f3e2;4286 result += id->alignment * 0xd3b3f3e2;
4148 for (size_t i = 0; i < id->param_count; i += 1) {4287 for (size_t i = 0; i < id->param_count; i += 1) {
4149 FnTypeParamInfo *info = &id->param_info[i];4288 FnTypeParamInfo *info = &id->param_info[i];
...@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {...@@ -4158,8 +4297,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
4158 a->return_type != b->return_type ||4297 a->return_type != b->return_type ||
4159 a->is_var_args != b->is_var_args ||4298 a->is_var_args != b->is_var_args ||
4160 a->param_count != b->param_count ||4299 a->param_count != b->param_count ||
4161 a->alignment != b->alignment ||4300 a->alignment != b->alignment)
4162 a->async_allocator_type != b->async_allocator_type)
4163 {4301 {
4164 return false;4302 return false;
4165 }4303 }
...@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4321,9 +4459,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4321 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);4459 return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
4322 case ZigTypeIdPointer:4460 case ZigTypeIdPointer:
4323 return hash_const_val_ptr(const_val);4461 return hash_const_val_ptr(const_val);
4324 case ZigTypeIdPromise:
4325 // TODO better hashing algorithm
4326 return 223048345;
4327 case ZigTypeIdUndefined:4462 case ZigTypeIdUndefined:
4328 return 162837799;4463 return 162837799;
4329 case ZigTypeIdNull:4464 case ZigTypeIdNull:
...@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4357,6 +4492,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4357 case ZigTypeIdVector:4492 case ZigTypeIdVector:
4358 // TODO better hashing algorithm4493 // TODO better hashing algorithm
4359 return 3647867726;4494 return 3647867726;
4495 case ZigTypeIdFnFrame:
4496 // TODO better hashing algorithm
4497 return 675741936;
4498 case ZigTypeIdAnyFrame:
4499 // TODO better hashing algorithm
4500 return 3747294894;
4360 case ZigTypeIdBoundFn:4501 case ZigTypeIdBoundFn:
4361 case ZigTypeIdInvalid:4502 case ZigTypeIdInvalid:
4362 case ZigTypeIdUnreachable:4503 case ZigTypeIdUnreachable:
...@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {...@@ -4389,7 +4530,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
4389 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {4530 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
4390 assert(a_val->special == ConstValSpecialStatic);4531 assert(a_val->special == ConstValSpecialStatic);
4391 assert(b_val->special == ConstValSpecialStatic);4532 assert(b_val->special == ConstValSpecialStatic);
4392 if (!const_values_equal(a->fn_entry->codegen, a_val, b_val)) {4533 if (!const_values_equal(a->codegen, a_val, b_val)) {
4393 return false;4534 return false;
4394 }4535 }
4395 } else {4536 } else {
...@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {...@@ -4419,9 +4560,10 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
4419 case ZigTypeIdBoundFn:4560 case ZigTypeIdBoundFn:
4420 case ZigTypeIdFn:4561 case ZigTypeIdFn:
4421 case ZigTypeIdOpaque:4562 case ZigTypeIdOpaque:
4422 case ZigTypeIdPromise:
4423 case ZigTypeIdErrorSet:4563 case ZigTypeIdErrorSet:
4424 case ZigTypeIdEnum:4564 case ZigTypeIdEnum:
4565 case ZigTypeIdFnFrame:
4566 case ZigTypeIdAnyFrame:
4425 return false;4567 return false;
44264568
4427 case ZigTypeIdPointer:4569 case ZigTypeIdPointer:
...@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {...@@ -4489,11 +4631,12 @@ static bool return_type_is_cacheable(ZigType *return_type) {
4489 case ZigTypeIdBoundFn:4631 case ZigTypeIdBoundFn:
4490 case ZigTypeIdFn:4632 case ZigTypeIdFn:
4491 case ZigTypeIdOpaque:4633 case ZigTypeIdOpaque:
4492 case ZigTypeIdPromise:
4493 case ZigTypeIdErrorSet:4634 case ZigTypeIdErrorSet:
4494 case ZigTypeIdEnum:4635 case ZigTypeIdEnum:
4495 case ZigTypeIdPointer:4636 case ZigTypeIdPointer:
4496 case ZigTypeIdVector:4637 case ZigTypeIdVector:
4638 case ZigTypeIdFnFrame:
4639 case ZigTypeIdAnyFrame:
4497 return true;4640 return true;
44984641
4499 case ZigTypeIdArray:4642 case ZigTypeIdArray:
...@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {...@@ -4624,8 +4767,9 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
4624 case ZigTypeIdFn:4767 case ZigTypeIdFn:
4625 case ZigTypeIdBool:4768 case ZigTypeIdBool:
4626 case ZigTypeIdFloat:4769 case ZigTypeIdFloat:
4627 case ZigTypeIdPromise:
4628 case ZigTypeIdErrorUnion:4770 case ZigTypeIdErrorUnion:
4771 case ZigTypeIdFnFrame:
4772 case ZigTypeIdAnyFrame:
4629 return OnePossibleValueNo;4773 return OnePossibleValueNo;
4630 case ZigTypeIdUndefined:4774 case ZigTypeIdUndefined:
4631 case ZigTypeIdNull:4775 case ZigTypeIdNull:
...@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {...@@ -4713,7 +4857,8 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
4713 case ZigTypeIdFloat:4857 case ZigTypeIdFloat:
4714 case ZigTypeIdVoid:4858 case ZigTypeIdVoid:
4715 case ZigTypeIdUnreachable:4859 case ZigTypeIdUnreachable:
4716 case ZigTypeIdPromise:4860 case ZigTypeIdFnFrame:
4861 case ZigTypeIdAnyFrame:
4717 return ReqCompTimeNo;4862 return ReqCompTimeNo;
4718 }4863 }
4719 zig_unreachable();4864 zig_unreachable();
...@@ -5032,6 +5177,223 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {...@@ -5032,6 +5177,223 @@ Error ensure_complete_type(CodeGen *g, ZigType *type_entry) {
5032 return type_resolve(g, type_entry, ResolveStatusSizeKnown);5177 return type_resolve(g, type_entry, ResolveStatusSizeKnown);
5033}5178}
50345179
5180static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) {
5181 if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync)
5182 return orig_fn_type;
5183
5184 ZigType *fn_type = allocate_nonzero<ZigType>(1);
5185 *fn_type = *orig_fn_type;
5186 fn_type->data.fn.fn_type_id.cc = CallingConventionAsync;
5187 fn_type->llvm_type = nullptr;
5188 fn_type->llvm_di_type = nullptr;
5189
5190 return fn_type;
5191}
5192
5193static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
5194 Error err;
5195
5196 if (frame_type->data.frame.locals_struct != nullptr)
5197 return ErrorNone;
5198
5199 ZigFn *fn = frame_type->data.frame.fn;
5200 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
5035Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {5397Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5036 if (type_is_invalid(ty))5398 if (type_is_invalid(ty))
5037 return ErrorSemanticAnalyzeFail;5399 return ErrorSemanticAnalyzeFail;
...@@ -5056,6 +5418,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {...@@ -5056,6 +5418,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5056 return resolve_enum_zero_bits(g, ty);5418 return resolve_enum_zero_bits(g, ty);
5057 } else if (ty->id == ZigTypeIdUnion) {5419 } else if (ty->id == ZigTypeIdUnion) {
5058 return resolve_union_alignment(g, ty);5420 return resolve_union_alignment(g, ty);
5421 } else if (ty->id == ZigTypeIdFnFrame) {
5422 return resolve_async_frame(g, ty);
5059 }5423 }
5060 return ErrorNone;5424 return ErrorNone;
5061 case ResolveStatusSizeKnown:5425 case ResolveStatusSizeKnown:
...@@ -5065,6 +5429,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {...@@ -5065,6 +5429,8 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
5065 return resolve_enum_zero_bits(g, ty);5429 return resolve_enum_zero_bits(g, ty);
5066 } else if (ty->id == ZigTypeIdUnion) {5430 } else if (ty->id == ZigTypeIdUnion) {
5067 return resolve_union_type(g, ty);5431 return resolve_union_type(g, ty);
5432 } else if (ty->id == ZigTypeIdFnFrame) {
5433 return resolve_async_frame(g, ty);
5068 }5434 }
5069 return ErrorNone;5435 return ErrorNone;
5070 case ResolveStatusLLVMFwdDecl:5436 case ResolveStatusLLVMFwdDecl:
...@@ -5259,6 +5625,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {...@@ -5259,6 +5625,10 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
5259 return false;5625 return false;
5260 }5626 }
5261 return true;5627 return true;
5628 case ZigTypeIdFnFrame:
5629 zig_panic("TODO");
5630 case ZigTypeIdAnyFrame:
5631 zig_panic("TODO");
5262 case ZigTypeIdUndefined:5632 case ZigTypeIdUndefined:
5263 zig_panic("TODO");5633 zig_panic("TODO");
5264 case ZigTypeIdNull:5634 case ZigTypeIdNull:
...@@ -5279,7 +5649,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {...@@ -5279,7 +5649,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
5279 case ZigTypeIdBoundFn:5649 case ZigTypeIdBoundFn:
5280 case ZigTypeIdInvalid:5650 case ZigTypeIdInvalid:
5281 case ZigTypeIdUnreachable:5651 case ZigTypeIdUnreachable:
5282 case ZigTypeIdPromise:
5283 zig_unreachable();5652 zig_unreachable();
5284 }5653 }
5285 zig_unreachable();5654 zig_unreachable();
...@@ -5612,8 +5981,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {...@@ -5612,8 +5981,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
5612 buf_appendf(buf, "(args value)");5981 buf_appendf(buf, "(args value)");
5613 return;5982 return;
5614 }5983 }
5615 case ZigTypeIdPromise:5984 case ZigTypeIdFnFrame:
5616 zig_unreachable();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
5617 }5992 }
5618 zig_unreachable();5993 zig_unreachable();
5619}5994}
...@@ -5627,6 +6002,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {...@@ -5627,6 +6002,15 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
5627 entry->llvm_type = LLVMIntType(size_in_bits);6002 entry->llvm_type = LLVMIntType(size_in_bits);
5628 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);6003 entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type);
5629 entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type);6004 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 }
5630 }6014 }
56316015
5632 const char u_or_i = is_signed ? 'i' : 'u';6016 const char u_or_i = is_signed ? 'i' : 'u';
...@@ -5660,7 +6044,8 @@ uint32_t type_id_hash(TypeId x) {...@@ -5660,7 +6044,8 @@ uint32_t type_id_hash(TypeId x) {
5660 case ZigTypeIdFn:6044 case ZigTypeIdFn:
5661 case ZigTypeIdBoundFn:6045 case ZigTypeIdBoundFn:
5662 case ZigTypeIdArgTuple:6046 case ZigTypeIdArgTuple:
5663 case ZigTypeIdPromise:6047 case ZigTypeIdFnFrame:
6048 case ZigTypeIdAnyFrame:
5664 zig_unreachable();6049 zig_unreachable();
5665 case ZigTypeIdErrorUnion:6050 case ZigTypeIdErrorUnion:
5666 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);6051 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) {...@@ -5702,7 +6087,6 @@ bool type_id_eql(TypeId a, TypeId b) {
5702 case ZigTypeIdUndefined:6087 case ZigTypeIdUndefined:
5703 case ZigTypeIdNull:6088 case ZigTypeIdNull:
5704 case ZigTypeIdOptional:6089 case ZigTypeIdOptional:
5705 case ZigTypeIdPromise:
5706 case ZigTypeIdErrorSet:6090 case ZigTypeIdErrorSet:
5707 case ZigTypeIdEnum:6091 case ZigTypeIdEnum:
5708 case ZigTypeIdUnion:6092 case ZigTypeIdUnion:
...@@ -5710,6 +6094,8 @@ bool type_id_eql(TypeId a, TypeId b) {...@@ -5710,6 +6094,8 @@ bool type_id_eql(TypeId a, TypeId b) {
5710 case ZigTypeIdBoundFn:6094 case ZigTypeIdBoundFn:
5711 case ZigTypeIdArgTuple:6095 case ZigTypeIdArgTuple:
5712 case ZigTypeIdOpaque:6096 case ZigTypeIdOpaque:
6097 case ZigTypeIdFnFrame:
6098 case ZigTypeIdAnyFrame:
5713 zig_unreachable();6099 zig_unreachable();
5714 case ZigTypeIdErrorUnion:6100 case ZigTypeIdErrorUnion:
5715 return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&6101 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[] = {...@@ -5875,7 +6261,8 @@ static const ZigTypeId all_type_ids[] = {
5875 ZigTypeIdBoundFn,6261 ZigTypeIdBoundFn,
5876 ZigTypeIdArgTuple,6262 ZigTypeIdArgTuple,
5877 ZigTypeIdOpaque,6263 ZigTypeIdOpaque,
5878 ZigTypeIdPromise,6264 ZigTypeIdFnFrame,
6265 ZigTypeIdAnyFrame,
5879 ZigTypeIdVector,6266 ZigTypeIdVector,
5880 ZigTypeIdEnumLiteral,6267 ZigTypeIdEnumLiteral,
5881};6268};
...@@ -5939,12 +6326,14 @@ size_t type_id_index(ZigType *entry) {...@@ -5939,12 +6326,14 @@ size_t type_id_index(ZigType *entry) {
5939 return 20;6326 return 20;
5940 case ZigTypeIdOpaque:6327 case ZigTypeIdOpaque:
5941 return 21;6328 return 21;
5942 case ZigTypeIdPromise:6329 case ZigTypeIdFnFrame:
5943 return 22;6330 return 22;
5944 case ZigTypeIdVector:6331 case ZigTypeIdAnyFrame:
5945 return 23;6332 return 23;
5946 case ZigTypeIdEnumLiteral:6333 case ZigTypeIdVector:
5947 return 24;6334 return 24;
6335 case ZigTypeIdEnumLiteral:
6336 return 25;
5948 }6337 }
5949 zig_unreachable();6338 zig_unreachable();
5950}6339}
...@@ -5999,10 +6388,12 @@ const char *type_id_name(ZigTypeId id) {...@@ -5999,10 +6388,12 @@ const char *type_id_name(ZigTypeId id) {
5999 return "ArgTuple";6388 return "ArgTuple";
6000 case ZigTypeIdOpaque:6389 case ZigTypeIdOpaque:
6001 return "Opaque";6390 return "Opaque";
6002 case ZigTypeIdPromise:
6003 return "Promise";
6004 case ZigTypeIdVector:6391 case ZigTypeIdVector:
6005 return "Vector";6392 return "Vector";
6393 case ZigTypeIdFnFrame:
6394 return "Frame";
6395 case ZigTypeIdAnyFrame:
6396 return "AnyFrame";
6006 }6397 }
6007 zig_unreachable();6398 zig_unreachable();
6008}6399}
...@@ -6067,19 +6458,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {...@@ -6067,19 +6458,12 @@ bool type_is_global_error_set(ZigType *err_set_type) {
6067 return err_set_type->data.error_set.err_count == UINT32_MAX;6458 return err_set_type->data.error_set.err_count == UINT32_MAX;
6068}6459}
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
6077bool type_can_fail(ZigType *type_entry) {6461bool type_can_fail(ZigType *type_entry) {
6078 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;6462 return type_entry->id == ZigTypeIdErrorUnion || type_entry->id == ZigTypeIdErrorSet;
6079}6463}
60806464
6081bool fn_type_can_fail(FnTypeId *fn_type_id) {6465bool 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);
6083}6467}
60846468
6085// ErrorNone - result pointer has the type6469// ErrorNone - result pointer has the type
...@@ -6449,7 +6833,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa...@@ -6449,7 +6833,9 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa
6449 type->data.structure.resolve_status = ResolveStatusLLVMFull;6833 type->data.structure.resolve_status = ResolveStatusLLVMFull;
6450}6834}
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{
6453 assert(struct_type->id == ZigTypeIdStruct);6839 assert(struct_type->id == ZigTypeIdStruct);
6454 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);6840 assert(struct_type->data.structure.resolve_status != ResolveStatusInvalid);
6455 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);6841 assert(struct_type->data.structure.resolve_status >= ResolveStatusSizeKnown);
...@@ -6486,10 +6872,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6486,10 +6872,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6486 }6872 }
64876873
6488 size_t field_count = struct_type->data.structure.src_field_count;6874 size_t field_count = struct_type->data.structure.src_field_count;
6489 size_t gen_field_count = struct_type->data.structure.gen_field_count;6875 // Every field could potentially have a generated padding field after it.
6490 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(gen_field_count);6876 LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count * 2);
64916877
6492 size_t gen_field_index = 0;
6493 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);6878 bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked);
6494 size_t packed_bits_offset = 0;6879 size_t packed_bits_offset = 0;
6495 size_t first_packed_bits_offset_misalign = SIZE_MAX;6880 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...@@ -6497,20 +6882,36 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
64976882
6498 // trigger all the recursive get_llvm_type calls6883 // trigger all the recursive get_llvm_type calls
6499 for (size_t i = 0; i < field_count; i += 1) {6884 for (size_t i = 0; i < field_count; i += 1) {
6500 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];6885 TypeStructField *field = &struct_type->data.structure.fields[i];
6501 ZigType *field_type = type_struct_field->type_entry;6886 ZigType *field_type = field->type_entry;
6502 if (!type_has_bits(field_type))6887 if (!type_has_bits(field_type))
6503 continue;6888 continue;
6504 (void)get_llvm_type(g, field_type);6889 (void)get_llvm_type(g, field_type);
6505 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;6890 if (struct_type->data.structure.resolve_status >= wanted_resolve_status) return;
6506 }6891 }
65076892
6508 for (size_t i = 0; i < field_count; i += 1) {6893 size_t gen_field_index = 0;
6509 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
6510 ZigType *field_type = type_struct_field->type_entry;
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;
6512 if (!type_has_bits(field_type))6900 if (!type_has_bits(field_type))
6513 continue;6901 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
6515 if (packed) {6916 if (packed) {
6516 size_t field_size_in_bits = type_size_bits(g, field_type);6917 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...@@ -6537,12 +6938,61 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6537 }6938 }
6538 packed_bits_offset = next_packed_bits_offset;6939 packed_bits_offset = next_packed_bits_offset;
6539 } else {6940 } else {
6540 element_types[gen_field_index] = get_llvm_type(g, field_type);6941 LLVMTypeRef llvm_type;
65416942 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;
6542 gen_field_index += 1;6952 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 }
6543 }6989 }
6544 debug_field_count += 1;6990 debug_field_count += 1;
6545 }6991 }
6992 if (!packed) {
6993 struct_type->data.structure.gen_field_count = gen_field_index;
6994 }
6995
6546 if (first_packed_bits_offset_misalign != SIZE_MAX) {6996 if (first_packed_bits_offset_misalign != SIZE_MAX) {
6547 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;6997 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
6548 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);6998 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...@@ -6551,19 +7001,20 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6551 }7001 }
65527002
6553 if (type_has_bits(struct_type)) {7003 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);
6555 }7006 }
65567007
6557 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);7008 ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(debug_field_count);
6558 size_t debug_field_index = 0;7009 size_t debug_field_index = 0;
6559 for (size_t i = 0; i < field_count; i += 1) {7010 for (size_t i = 0; i < field_count; i += 1) {
6560 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];7011 TypeStructField *field = &struct_type->data.structure.fields[i];
6561 size_t gen_field_index = type_struct_field->gen_index;7012 size_t gen_field_index = field->gen_index;
6562 if (gen_field_index == SIZE_MAX) {7013 if (gen_field_index == SIZE_MAX) {
6563 continue;7014 continue;
6564 }7015 }
65657016
6566 ZigType *field_type = type_struct_field->type_entry;7017 ZigType *field_type = field->type_entry;
65677018
6568 // if the field is a function, actually the debug info should be a pointer.7019 // if the field is a function, actually the debug info should be a pointer.
6569 ZigLLVMDIType *field_di_type;7020 ZigLLVMDIType *field_di_type;
...@@ -6581,13 +7032,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6581,13 +7032,13 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6581 uint64_t debug_align_in_bits;7032 uint64_t debug_align_in_bits;
6582 uint64_t debug_offset_in_bits;7033 uint64_t debug_offset_in_bits;
6583 if (packed) {7034 if (packed) {
6584 debug_size_in_bits = type_struct_field->type_entry->size_in_bits;7035 debug_size_in_bits = field->type_entry->size_in_bits;
6585 debug_align_in_bits = 8 * type_struct_field->type_entry->abi_align;7036 debug_align_in_bits = 8 * field->type_entry->abi_align;
6586 debug_offset_in_bits = 8 * type_struct_field->offset + type_struct_field->bit_offset_in_host;7037 debug_offset_in_bits = 8 * field->offset + field->bit_offset_in_host;
6587 } else {7038 } else {
6588 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);7039 debug_size_in_bits = 8 * get_store_size_bytes(field_type->size_in_bits);
6589 debug_align_in_bits = 8 * field_type->abi_align;7040 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;
6591 }7042 }
6592 unsigned line;7043 unsigned line;
6593 if (decl_node != nullptr) {7044 if (decl_node != nullptr) {
...@@ -6597,7 +7048,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -6597,7 +7048,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
6597 line = 0;7048 line = 0;
6598 }7049 }
6599 di_element_types[debug_field_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,7050 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),
6601 di_file, line,7052 di_file, line,
6602 debug_size_in_bits,7053 debug_size_in_bits,
6603 debug_align_in_bits,7054 debug_align_in_bits,
...@@ -6838,7 +7289,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta...@@ -6838,7 +7289,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
6838 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;7289 union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
6839}7290}
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) {
6842 if (type->llvm_di_type != nullptr) return;7293 if (type->llvm_di_type != nullptr) return;
68437294
6844 if (!type_has_bits(type)) {7295 if (!type_has_bits(type)) {
...@@ -6867,7 +7318,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {...@@ -6867,7 +7318,7 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type) {
6867 uint64_t debug_align_in_bits = 8*type->abi_align;7318 uint64_t debug_align_in_bits = 8*type->abi_align;
6868 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,7319 type->llvm_di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, elem_type->llvm_di_type,
6869 debug_size_in_bits, debug_align_in_bits, buf_ptr(&type->name));7320 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));
6871 } else {7322 } else {
6872 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);7323 ZigType *host_int_type = get_int_type(g, false, type->data.pointer.host_int_bytes * 8);
6873 LLVMTypeRef host_int_llvm_type = get_llvm_type(g, host_int_type);7324 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) {...@@ -6993,10 +7444,17 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
6993 } else {7444 } else {
6994 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);7445 LLVMTypeRef err_set_llvm_type = get_llvm_type(g, err_set_type);
6995 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);7446 LLVMTypeRef payload_llvm_type = get_llvm_type(g, payload_type);
6996 LLVMTypeRef elem_types[2];7447 LLVMTypeRef elem_types[3];
6997 elem_types[err_union_err_index] = err_set_llvm_type;7448 elem_types[err_union_err_index] = err_set_llvm_type;
6998 elem_types[err_union_payload_index] = payload_llvm_type;7449 elem_types[err_union_payload_index] = payload_llvm_type;
7450
6999 type->llvm_type = LLVMStructType(elem_types, 2, false);7451 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
7001 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);7459 ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7002 ZigLLVMDIFile *di_file = nullptr;7460 ZigLLVMDIFile *di_file = nullptr;
...@@ -7017,20 +7475,21 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {...@@ -7017,20 +7475,21 @@ static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
7017 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);7475 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type);
7018 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);7476 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type);
70197477
7020 ZigLLVMDIType *di_element_types[] = {7478 ZigLLVMDIType *di_element_types[2];
7021 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),7479 di_element_types[err_union_err_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
7480 ZigLLVMTypeToScope(type->llvm_di_type),
7022 "tag", di_file, line,7481 "tag", di_file, line,
7023 tag_debug_size_in_bits,7482 tag_debug_size_in_bits,
7024 tag_debug_align_in_bits,7483 tag_debug_align_in_bits,
7025 tag_offset_in_bits,7484 tag_offset_in_bits,
7026 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type)),7485 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, err_set_type));
7027 ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(type->llvm_di_type),7486 di_element_types[err_union_payload_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
7487 ZigLLVMTypeToScope(type->llvm_di_type),
7028 "value", di_file, line,7488 "value", di_file, line,
7029 value_debug_size_in_bits,7489 value_debug_size_in_bits,
7030 value_debug_align_in_bits,7490 value_debug_align_in_bits,
7031 value_offset_in_bits,7491 value_offset_in_bits,
7032 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type)),7492 ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, payload_type));
7033 };
70347493
7035 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,7494 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
7036 compile_unit_scope,7495 compile_unit_scope,
...@@ -7067,7 +7526,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {...@@ -7067,7 +7526,7 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) {
7067 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);7526 debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len);
7068}7527}
70697528
7070static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {7529static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7071 if (fn_type->llvm_di_type != nullptr) return;7530 if (fn_type->llvm_di_type != nullptr) return;
70727531
7073 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;7532 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) {...@@ -7084,67 +7543,73 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7084 // +1 for maybe first argument the error return trace7543 // +1 for maybe first argument the error return trace
7085 // +2 for maybe arguments async allocator and error code pointer7544 // +2 for maybe arguments async allocator and error code pointer
7086 ZigList<ZigLLVMDIType *> param_di_types = {};7545 ZigList<ZigLLVMDIType *> param_di_types = {};
7087 param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
7088 ZigType *gen_return_type;7546 ZigType *gen_return_type;
7089 if (is_async) {7547 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));
7091 } else if (!type_has_bits(fn_type_id->return_type)) {7550 } else if (!type_has_bits(fn_type_id->return_type)) {
7092 gen_return_type = g->builtin_types.entry_void;7551 gen_return_type = g->builtin_types.entry_void;
7552 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7093 } else if (first_arg_return) {7553 } 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));
7094 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);7556 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
7095 gen_param_types.append(get_llvm_type(g, gen_type));7557 gen_param_types.append(get_llvm_type(g, gen_type));
7096 param_di_types.append(get_llvm_di_type(g, gen_type));7558 param_di_types.append(get_llvm_di_type(g, gen_type));
7097 gen_return_type = g->builtin_types.entry_void;
7098 } else {7559 } else {
7099 gen_return_type = fn_type_id->return_type;7560 gen_return_type = fn_type_id->return_type;
7561 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7100 }7562 }
7101 fn_type->data.fn.gen_return_type = gen_return_type;7563 fn_type->data.fn.gen_return_type = gen_return_type;
71027564
7103 if (prefix_arg_error_return_trace) {7565 if (prefix_arg_error_return_trace && !is_async) {
7104 ZigType *gen_type = get_ptr_to_stack_trace_type(g);7566 ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false);
7105 gen_param_types.append(get_llvm_type(g, gen_type));7567 gen_param_types.append(get_llvm_type(g, gen_type));
7106 param_di_types.append(get_llvm_di_type(g, gen_type));7568 param_di_types.append(get_llvm_di_type(g, gen_type));
7107 }7569 }
7108 if (is_async) {7570 if (is_async) {
7109 {7571 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(2);
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 }
71157572
7116 {7573 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7117 // error code pointer7574 gen_param_types.append(get_llvm_type(g, frame_type));
7118 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);7575 param_di_types.append(get_llvm_di_type(g, frame_type));
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 }
71237576
7124 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);7577 fn_type->data.fn.gen_param_info[0].src_index = 0;
7125 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {7578 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7126 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];7579 fn_type->data.fn.gen_param_info[0].type = frame_type;
7127 ZigType *type_entry = src_param_info->type;
7128 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
71297580
7130 gen_param_info->src_index = i;7581 gen_param_types.append(get_llvm_type(g, g->builtin_types.entry_usize));
7131 gen_param_info->gen_index = SIZE_MAX;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))7584 fn_type->data.fn.gen_param_info[1].src_index = 1;
7134 continue;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;7594 gen_param_info->src_index = i;
7137 if (handle_is_ptr(type_entry)) {7595 gen_param_info->gen_index = SIZE_MAX;
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));
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 }
7148 }7613 }
71497614
7150 if (is_c_abi) {7615 if (is_c_abi) {
...@@ -7160,6 +7625,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {...@@ -7160,6 +7625,7 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7160 for (size_t i = 0; i < gen_param_types.length; i += 1) {7625 for (size_t i = 0; i < gen_param_types.length; i += 1) {
7161 assert(gen_param_types.items[i] != nullptr);7626 assert(gen_param_types.items[i] != nullptr);
7162 }7627 }
7628
7163 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),7629 fn_type->data.fn.raw_type_ref = LLVMFunctionType(get_llvm_type(g, gen_return_type),
7164 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);7630 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
7165 fn_type->llvm_type = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);7631 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) {...@@ -7169,6 +7635,40 @@ static void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type) {
7169 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");7635 LLVMABIAlignmentOfType(g->target_data_ref, fn_type->llvm_type), "");
7170}7636}
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
7172static void resolve_llvm_types_anyerror(CodeGen *g) {7672static void resolve_llvm_types_anyerror(CodeGen *g) {
7173 ZigType *entry = g->builtin_types.entry_global_error_set;7673 ZigType *entry = g->builtin_types.entry_global_error_set;
7174 entry->llvm_type = get_llvm_type(g, g->err_tag_type);7674 entry->llvm_type = get_llvm_type(g, g->err_tag_type);
...@@ -7193,6 +7693,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {...@@ -7193,6 +7693,147 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
7193 get_llvm_di_type(g, g->err_tag_type), "");7693 get_llvm_di_type(g, g->err_tag_type), "");
7194}7694}
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
7196static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {7837static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
7197 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));7838 assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
7198 assert(wanted_resolve_status > ResolveStatusSizeKnown);7839 assert(wanted_resolve_status > ResolveStatusSizeKnown);
...@@ -7218,20 +7859,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7218,20 +7859,13 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7218 if (type->data.structure.is_slice)7859 if (type->data.structure.is_slice)
7219 return resolve_llvm_types_slice(g, type, wanted_resolve_status);7860 return resolve_llvm_types_slice(g, type, wanted_resolve_status);
7220 else7861 else
7221 return resolve_llvm_types_struct(g, type, wanted_resolve_status);7862 return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr);
7222 case ZigTypeIdEnum:7863 case ZigTypeIdEnum:
7223 return resolve_llvm_types_enum(g, type);7864 return resolve_llvm_types_enum(g, type);
7224 case ZigTypeIdUnion:7865 case ZigTypeIdUnion:
7225 return resolve_llvm_types_union(g, type, wanted_resolve_status);7866 return resolve_llvm_types_union(g, type, wanted_resolve_status);
7226 case ZigTypeIdPointer:7867 case ZigTypeIdPointer:
7227 return resolve_llvm_types_pointer(g, type);7868 return resolve_llvm_types_pointer(g, type, wanted_resolve_status);
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 }
7235 case ZigTypeIdInt:7869 case ZigTypeIdInt:
7236 return resolve_llvm_types_integer(g, type);7870 return resolve_llvm_types_integer(g, type);
7237 case ZigTypeIdOptional:7871 case ZigTypeIdOptional:
...@@ -7241,7 +7875,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7241,7 +7875,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7241 case ZigTypeIdArray:7875 case ZigTypeIdArray:
7242 return resolve_llvm_types_array(g, type);7876 return resolve_llvm_types_array(g, type);
7243 case ZigTypeIdFn:7877 case ZigTypeIdFn:
7244 return resolve_llvm_types_fn(g, type);7878 return resolve_llvm_types_fn_type(g, type);
7245 case ZigTypeIdErrorSet: {7879 case ZigTypeIdErrorSet: {
7246 if (type->llvm_di_type != nullptr) return;7880 if (type->llvm_di_type != nullptr) return;
72477881
...@@ -7260,14 +7894,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r...@@ -7260,14 +7894,18 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
7260 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);7894 type->abi_align, get_llvm_di_type(g, type->data.vector.elem_type), type->data.vector.len);
7261 return;7895 return;
7262 }7896 }
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);
7263 }7901 }
7264 zig_unreachable();7902 zig_unreachable();
7265}7903}
72667904
7267LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {7905LLVMTypeRef get_llvm_type(CodeGen *g, ZigType *type) {
7268 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));7906 assertNoError(type_resolve(g, type, ResolveStatusLLVMFull));
7269 assert(type->abi_size == 0 || type->abi_size == LLVMABISizeOfType(g->target_data_ref, type->llvm_type));7907 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));7908 assert(type->abi_align == 0 || type->abi_align >= LLVMABIAlignmentOfType(g->target_data_ref, type->llvm_type));
7271 return type->llvm_type;7909 return type->llvm_type;
7272}7910}
72737911
src/analyze.hpp+8-10
...@@ -11,11 +11,12 @@...@@ -11,11 +11,12 @@
11#include "all_types.hpp"11#include "all_types.hpp"
1212
13void semantic_analyze(CodeGen *g);13void semantic_analyze(CodeGen *g);
14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);14ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg);
15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg);
17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
18ZigType *new_type_table_entry(ZigTypeId id);18ZigType *new_type_table_entry(ZigTypeId id);
19ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
19ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);20ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
20ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,21ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
21 bool is_volatile, PtrLen ptr_len,22 bool is_volatile, PtrLen ptr_len,
...@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);...@@ -37,11 +38,8 @@ ZigType *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
37ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);38ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payload_type);
38ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);39ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry);
39ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);40ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name);
40ZigType *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
41 ZigType *field_types[], size_t field_count);
42ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
43ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type);
44ZigType *get_test_fn_type(CodeGen *g);41ZigType *get_test_fn_type(CodeGen *g);
42ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
45bool handle_is_ptr(ZigType *type_entry);43bool handle_is_ptr(ZigType *type_entry);
4644
47bool type_has_bits(ZigType *type_entry);45bool type_has_bits(ZigType *type_entry);
...@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v...@@ -106,7 +104,6 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
106void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);104void eval_min_max_value_int(CodeGen *g, ZigType *int_type, BigInt *bigint, bool is_max);
107105
108void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);106void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
109void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node);
110107
111ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);108ScopeBlock *create_block_scope(CodeGen *g, AstNode *node, Scope *parent);
112ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);109ScopeDefer *create_defer_scope(CodeGen *g, AstNode *node, Scope *parent);
...@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);...@@ -117,7 +114,6 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
117ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);114ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
118ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);115ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
119Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);116Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
120Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent);
121Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);117Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
122118
123void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
...@@ -199,12 +195,11 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global...@@ -199,12 +195,11 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global
199195
200196
201ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);197ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
202ZigType *get_ptr_to_stack_trace_type(CodeGen *g);198ZigType *get_stack_trace_type(CodeGen *g);
203bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);199bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node);
204200
205ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);201ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry);
206202
207uint32_t get_coro_frame_align_bytes(CodeGen *g);
208bool fn_type_can_fail(FnTypeId *fn_type_id);203bool fn_type_can_fail(FnTypeId *fn_type_id);
209bool type_can_fail(ZigType *type_entry);204bool type_can_fail(ZigType *type_entry);
210bool fn_eval_cacheable(Scope *scope, ZigType *return_type);205bool fn_eval_cacheable(Scope *scope, ZigType *return_type);
...@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);...@@ -251,4 +246,7 @@ void src_assert(bool ok, AstNode *source_node);
251bool is_container(ZigType *type_entry);246bool is_container(ZigType *type_entry);
252ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);247ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name);
253248
249void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
250bool fn_is_async(ZigFn *fn);
251
254#endif252#endif
src/ast_render.cpp+19-26
...@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {...@@ -249,18 +249,16 @@ static const char *node_type_str(NodeType node_type) {
249 return "IfOptional";249 return "IfOptional";
250 case NodeTypeErrorSetDecl:250 case NodeTypeErrorSetDecl:
251 return "ErrorSetDecl";251 return "ErrorSetDecl";
252 case NodeTypeCancel:
253 return "Cancel";
254 case NodeTypeResume:252 case NodeTypeResume:
255 return "Resume";253 return "Resume";
256 case NodeTypeAwaitExpr:254 case NodeTypeAwaitExpr:
257 return "AwaitExpr";255 return "AwaitExpr";
258 case NodeTypeSuspend:256 case NodeTypeSuspend:
259 return "Suspend";257 return "Suspend";
260 case NodeTypePromiseType:
261 return "PromiseType";
262 case NodeTypePointerType:258 case NodeTypePointerType:
263 return "PointerType";259 return "PointerType";
260 case NodeTypeAnyFrameType:
261 return "AnyFrameType";
264 case NodeTypeEnumLiteral:262 case NodeTypeEnumLiteral:
265 return "EnumLiteral";263 return "EnumLiteral";
266 }264 }
...@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -699,13 +697,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
699 fprintf(ar->f, "@");697 fprintf(ar->f, "@");
700 }698 }
701 if (node->data.fn_call_expr.is_async) {699 if (node->data.fn_call_expr.is_async) {
702 fprintf(ar->f, "async");700 fprintf(ar->f, "async ");
703 if (node->data.fn_call_expr.async_allocator != nullptr) {
704 fprintf(ar->f, "<");
705 render_node_extra(ar, node->data.fn_call_expr.async_allocator, true);
706 fprintf(ar->f, ">");
707 }
708 fprintf(ar->f, " ");
709 }701 }
710 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;702 AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
711 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);703 bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);
...@@ -862,15 +854,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -862,15 +854,14 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
862 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);854 render_node_ungrouped(ar, node->data.inferred_array_type.child_type);
863 break;855 break;
864 }856 }
865 case NodeTypePromiseType:857 case NodeTypeAnyFrameType: {
866 {858 fprintf(ar->f, "anyframe");
867 fprintf(ar->f, "promise");859 if (node->data.anyframe_type.payload_type != nullptr) {
868 if (node->data.promise_type.payload_type != nullptr) {860 fprintf(ar->f, "->");
869 fprintf(ar->f, "->");861 render_node_grouped(ar, node->data.anyframe_type.payload_type);
870 render_node_grouped(ar, node->data.promise_type.payload_type);
871 }
872 break;
873 }862 }
863 break;
864 }
874 case NodeTypeErrorType:865 case NodeTypeErrorType:
875 fprintf(ar->f, "anyerror");866 fprintf(ar->f, "anyerror");
876 break;867 break;
...@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1143,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1143 fprintf(ar->f, "}");1134 fprintf(ar->f, "}");
1144 break;1135 break;
1145 }1136 }
1146 case NodeTypeCancel:
1147 {
1148 fprintf(ar->f, "cancel ");
1149 render_node_grouped(ar, node->data.cancel_expr.expr);
1150 break;
1151 }
1152 case NodeTypeResume:1137 case NodeTypeResume:
1153 {1138 {
1154 fprintf(ar->f, "resume ");1139 fprintf(ar->f, "resume ");
...@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1163,9 +1148,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1163 }1148 }
1164 case NodeTypeSuspend:1149 case NodeTypeSuspend:
1165 {1150 {
1166 fprintf(ar->f, "suspend");
1167 if (node->data.suspend.block != nullptr) {1151 if (node->data.suspend.block != nullptr) {
1152 fprintf(ar->f, "suspend ");
1168 render_node_grouped(ar, node->data.suspend.block);1153 render_node_grouped(ar, node->data.suspend.block);
1154 } else {
1155 fprintf(ar->f, "suspend\n");
1169 }1156 }
1170 break;1157 break;
1171 }1158 }
...@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {...@@ -1191,3 +1178,9 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {
11911178
1192 render_node_grouped(&ar, node);1179 render_node_grouped(&ar, node);
1193}1180}
1181
1182void AstNode::src() {
1183 fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize "\n",
1184 buf_ptr(this->owner->data.structure.root_struct->path),
1185 this->line + 1, this->column + 1);
1186}
src/codegen.cpp+1248-943
...@@ -24,6 +24,12 @@...@@ -24,6 +24,12 @@
24#include <stdio.h>24#include <stdio.h>
25#include <errno.h>25#include <errno.h>
2626
27enum ResumeId {
28 ResumeIdManual,
29 ResumeIdReturn,
30 ResumeIdCall,
31};
32
27static void init_darwin_native(CodeGen *g) {33static void init_darwin_native(CodeGen *g) {
28 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");34 char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
29 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");35 char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
...@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {...@@ -297,12 +303,42 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
297 zig_unreachable();303 zig_unreachable();
298}304}
299305
306// label (grep this): [fn_frame_struct_layout]
307static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) {
308 // [0] *ReturnType (callee's)
309 // [1] *ReturnType (awaiter's)
310 // [2] ReturnType
311 uint32_t return_field_count = type_has_bits(return_type) ? 3 : 0;
312 return frame_ret_start + return_field_count;
313}
314
315// label (grep this): [fn_frame_struct_layout]
316static uint32_t frame_index_arg(CodeGen *g, ZigType *return_type) {
317 bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, return_type);
318 // [0] *StackTrace (callee's)
319 // [1] *StackTrace (awaiter's)
320 uint32_t trace_field_count = have_stack_trace ? 2 : 0;
321 return frame_index_trace_arg(g, return_type) + trace_field_count;
322}
323
324// label (grep this): [fn_frame_struct_layout]
325static uint32_t frame_index_trace_stack(CodeGen *g, FnTypeId *fn_type_id) {
326 uint32_t result = frame_index_arg(g, fn_type_id->return_type);
327 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
328 if (type_has_bits(fn_type_id->param_info->type)) {
329 result += 1;
330 }
331 }
332 return result;
333}
334
335
300static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {336static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
301 if (!g->have_err_ret_tracing) {337 if (!g->have_err_ret_tracing) {
302 return UINT32_MAX;338 return UINT32_MAX;
303 }339 }
304 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {340 if (fn_is_async(fn_table_entry)) {
305 return 0;341 return UINT32_MAX;
306 }342 }
307 ZigType *fn_type = fn_table_entry->type_entry;343 ZigType *fn_type = fn_table_entry->type_entry;
308 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {344 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
...@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {...@@ -343,27 +379,28 @@ static bool cc_want_sret_attr(CallingConvention cc) {
343 zig_unreachable();379 zig_unreachable();
344}380}
345381
346static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {382static bool codegen_have_frame_pointer(CodeGen *g) {
347 if (fn_table_entry->llvm_value)383 return g->build_mode == BuildModeDebug;
348 return fn_table_entry->llvm_value;384}
349385
350 Buf *unmangled_name = &fn_table_entry->symbol_name;386static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
387 Buf *unmangled_name = &fn->symbol_name;
351 Buf *symbol_name;388 Buf *symbol_name;
352 GlobalLinkageId linkage;389 GlobalLinkageId linkage;
353 if (fn_table_entry->body_node == nullptr) {390 if (fn->body_node == nullptr) {
354 symbol_name = unmangled_name;391 symbol_name = unmangled_name;
355 linkage = GlobalLinkageIdStrong;392 linkage = GlobalLinkageIdStrong;
356 } else if (fn_table_entry->export_list.length == 0) {393 } else if (fn->export_list.length == 0) {
357 symbol_name = get_mangled_name(g, unmangled_name, false);394 symbol_name = get_mangled_name(g, unmangled_name, false);
358 linkage = GlobalLinkageIdInternal;395 linkage = GlobalLinkageIdInternal;
359 } else {396 } else {
360 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];397 GlobalExport *fn_export = &fn->export_list.items[0];
361 symbol_name = &fn_export->name;398 symbol_name = &fn_export->name;
362 linkage = fn_export->linkage;399 linkage = fn_export->linkage;
363 }400 }
364401
365 bool external_linkage = linkage != GlobalLinkageIdInternal;402 bool external_linkage = linkage != GlobalLinkageIdInternal;
366 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;403 CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
367 if (cc == CallingConventionStdcall && external_linkage &&404 if (cc == CallingConventionStdcall && external_linkage &&
368 g->zig_target->arch == ZigLLVM_x86)405 g->zig_target->arch == ZigLLVM_x86)
369 {406 {
...@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -371,130 +408,125 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
371 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));408 symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
372 }409 }
373410
411 bool is_async = fn_is_async(fn);
374412
375 ZigType *fn_type = fn_table_entry->type_entry;413
414 ZigType *fn_type = fn->type_entry;
376 // Make the raw_type_ref populated415 // Make the raw_type_ref populated
377 (void)get_llvm_type(g, fn_type);416 resolve_llvm_types_fn(g, fn);
378 LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;417 LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
379 if (fn_table_entry->body_node == nullptr) {418 LLVMValueRef llvm_fn = nullptr;
419 if (fn->body_node == nullptr) {
380 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));420 LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
381 if (existing_llvm_fn) {421 if (existing_llvm_fn) {
382 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));422 return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
383 return fn_table_entry->llvm_value;
384 } else {423 } else {
385 auto entry = g->exported_symbol_names.maybe_get(symbol_name);424 auto entry = g->exported_symbol_names.maybe_get(symbol_name);
386 if (entry == nullptr) {425 if (entry == nullptr) {
387 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);426 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
388427
389 if (target_is_wasm(g->zig_target)) {428 if (target_is_wasm(g->zig_target)) {
390 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);429 assert(fn->proto_node->type == NodeTypeFnProto);
391 AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;430 AstNodeFnProto *fn_proto = &fn->proto_node->data.fn_proto;
392 if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {431 if (fn_proto-> is_extern && fn_proto->lib_name != nullptr ) {
393 addLLVMFnAttrStr(fn_table_entry->llvm_value, "wasm-import-module", buf_ptr(fn_proto->lib_name));432 addLLVMFnAttrStr(llvm_fn, "wasm-import-module", buf_ptr(fn_proto->lib_name));
394 }433 }
395 }434 }
396 } else {435 } else {
397 assert(entry->value->id == TldIdFn);436 assert(entry->value->id == TldIdFn);
398 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);437 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
399 // Make the raw_type_ref populated438 // Make the raw_type_ref populated
400 (void)get_llvm_type(g, tld_fn->fn_entry->type_entry);439 resolve_llvm_types_fn(g, tld_fn->fn_entry);
401 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),440 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
402 tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);441 tld_fn->fn_entry->raw_type_ref);
403 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,442 llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0));
404 LLVMPointerType(fn_llvm_type, 0));443 return llvm_fn;
405 return fn_table_entry->llvm_value;
406 }444 }
407 }445 }
408 } else {446 } else {
409 if (fn_table_entry->llvm_value == nullptr) {447 if (llvm_fn == nullptr) {
410 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);448 llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
411 }449 }
412450
413 for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {451 for (size_t i = 1; i < fn->export_list.length; i += 1) {
414 GlobalExport *fn_export = &fn_table_entry->export_list.items[i];452 GlobalExport *fn_export = &fn->export_list.items[i];
415 LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value),453 LLVMAddAlias(g->module, LLVMTypeOf(llvm_fn), llvm_fn, buf_ptr(&fn_export->name));
416 fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
417 }454 }
418 }455 }
419 fn_table_entry->llvm_name = strdup(LLVMGetValueName(fn_table_entry->llvm_value));
420456
421 switch (fn_table_entry->fn_inline) {457 switch (fn->fn_inline) {
422 case FnInlineAlways:458 case FnInlineAlways:
423 addLLVMFnAttr(fn_table_entry->llvm_value, "alwaysinline");459 addLLVMFnAttr(llvm_fn, "alwaysinline");
424 g->inline_fns.append(fn_table_entry);460 g->inline_fns.append(fn);
425 break;461 break;
426 case FnInlineNever:462 case FnInlineNever:
427 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");463 addLLVMFnAttr(llvm_fn, "noinline");
428 break;464 break;
429 case FnInlineAuto:465 case FnInlineAuto:
430 if (fn_table_entry->alignstack_value != 0) {466 if (fn->alignstack_value != 0) {
431 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");467 addLLVMFnAttr(llvm_fn, "noinline");
432 }468 }
433 break;469 break;
434 }470 }
435471
436 if (cc == CallingConventionNaked) {472 if (cc == CallingConventionNaked) {
437 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");473 addLLVMFnAttr(llvm_fn, "naked");
438 } else {474 } else {
439 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));475 LLVMSetFunctionCallConv(llvm_fn, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
440 }
441 if (cc == CallingConventionAsync) {
442 addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
443 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
444 }476 }
445477
446 bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;478 bool want_cold = fn->is_cold || cc == CallingConventionCold;
447 if (want_cold) {479 if (want_cold) {
448 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);480 ZigLLVMAddFunctionAttrCold(llvm_fn);
449 }481 }
450482
451483
452 LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage));484 LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage));
453485
454 if (linkage == GlobalLinkageIdInternal) {486 if (linkage == GlobalLinkageIdInternal) {
455 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);487 LLVMSetUnnamedAddr(llvm_fn, true);
456 }488 }
457489
458 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;490 ZigType *return_type = fn_type->data.fn.fn_type_id.return_type;
459 if (return_type->id == ZigTypeIdUnreachable) {491 if (return_type->id == ZigTypeIdUnreachable) {
460 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");492 addLLVMFnAttr(llvm_fn, "noreturn");
461 }493 }
462494
463 if (fn_table_entry->body_node != nullptr) {495 if (fn->body_node != nullptr) {
464 maybe_export_dll(g, fn_table_entry->llvm_value, linkage);496 maybe_export_dll(g, llvm_fn, linkage);
465497
466 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&498 bool want_fn_safety = g->build_mode != BuildModeFastRelease &&
467 g->build_mode != BuildModeSmallRelease &&499 g->build_mode != BuildModeSmallRelease &&
468 !fn_table_entry->def_scope->safety_off;500 !fn->def_scope->safety_off;
469 if (want_fn_safety) {501 if (want_fn_safety) {
470 if (g->libc_link_lib != nullptr) {502 if (g->libc_link_lib != nullptr) {
471 addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");503 addLLVMFnAttr(llvm_fn, "sspstrong");
472 addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");504 addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
473 }505 }
474 }506 }
475 if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) {507 if (g->have_stack_probing && !fn->def_scope->safety_off) {
476 addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack");508 addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack");
477 }509 }
478 } else {510 } else {
479 maybe_import_dll(g, fn_table_entry->llvm_value, linkage);511 maybe_import_dll(g, llvm_fn, linkage);
480 }512 }
481513
482 if (fn_table_entry->alignstack_value != 0) {514 if (fn->alignstack_value != 0) {
483 addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value);515 addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value);
484 }516 }
485517
486 addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind");518 addLLVMFnAttr(llvm_fn, "nounwind");
487 add_uwtable_attr(g, fn_table_entry->llvm_value);519 add_uwtable_attr(g, llvm_fn);
488 addLLVMFnAttr(fn_table_entry->llvm_value, "nobuiltin");520 addLLVMFnAttr(llvm_fn, "nobuiltin");
489 if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) {521 if (codegen_have_frame_pointer(g) && fn->fn_inline != FnInlineAlways) {
490 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");522 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim", "true");
491 ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);523 ZigLLVMAddFunctionAttr(llvm_fn, "no-frame-pointer-elim-non-leaf", nullptr);
492 }524 }
493 if (fn_table_entry->section_name) {525 if (fn->section_name) {
494 LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name));526 LLVMSetSection(llvm_fn, buf_ptr(fn->section_name));
495 }527 }
496 if (fn_table_entry->align_bytes > 0) {528 if (fn->align_bytes > 0) {
497 LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes);529 LLVMSetAlignment(llvm_fn, (unsigned)fn->align_bytes);
498 } else {530 } else {
499 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives531 // We'd like to set the best alignment for the function here, but on Darwin LLVM gives
500 // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling532 // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling
...@@ -502,36 +534,50 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {...@@ -502,36 +534,50 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
502 // use the ABI alignment, which is fine.534 // use the ABI alignment, which is fine.
503 }535 }
504536
505 unsigned init_gen_i = 0;537 if (is_async) {
506 if (!type_has_bits(return_type)) {538 addLLVMArgAttr(llvm_fn, 0, "nonnull");
507 // nothing to do539 } else {
508 } else if (type_is_nonnull_ptr(return_type)) {540 unsigned init_gen_i = 0;
509 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");541 if (!type_has_bits(return_type)) {
510 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {542 // nothing to do
511 // Sret pointers must not be address 0543 } else if (type_is_nonnull_ptr(return_type)) {
512 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");544 addLLVMAttr(llvm_fn, 0, "nonnull");
513 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");545 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
514 if (cc_want_sret_attr(cc)) {546 // Sret pointers must not be address 0
515 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");547 addLLVMArgAttr(llvm_fn, 0, "nonnull");
548 addLLVMArgAttr(llvm_fn, 0, "sret");
549 if (cc_want_sret_attr(cc)) {
550 addLLVMArgAttr(llvm_fn, 0, "noalias");
551 }
552 init_gen_i = 1;
516 }553 }
517 init_gen_i = 1;
518 }
519554
520 // set parameter attributes555 // set parameter attributes
521 FnWalk fn_walk = {};556 FnWalk fn_walk = {};
522 fn_walk.id = FnWalkIdAttrs;557 fn_walk.id = FnWalkIdAttrs;
523 fn_walk.data.attrs.fn = fn_table_entry;558 fn_walk.data.attrs.fn = fn;
524 fn_walk.data.attrs.gen_i = init_gen_i;559 fn_walk.data.attrs.llvm_fn = llvm_fn;
525 walk_function_params(g, fn_type, &fn_walk);560 fn_walk.data.attrs.gen_i = init_gen_i;
561 walk_function_params(g, fn_type, &fn_walk);
526562
527 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);563 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn);
528 if (err_ret_trace_arg_index != UINT32_MAX) {564 if (err_ret_trace_arg_index != UINT32_MAX) {
529 // Error return trace memory is in the stack, which is impossible to be at address 0565 // Error return trace memory is in the stack, which is impossible to be at address 0
530 // on any architecture.566 // on any architecture.
531 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");567 addLLVMArgAttr(llvm_fn, (unsigned)err_ret_trace_arg_index, "nonnull");
568 }
532 }569 }
533570
534 return fn_table_entry->llvm_value;571 return llvm_fn;
572}
573
574static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) {
575 if (fn->llvm_value)
576 return fn->llvm_value;
577
578 fn->llvm_value = make_fn_llvm_value(g, fn);
579 fn->llvm_name = strdup(LLVMGetValueName(fn->llvm_value));
580 return fn->llvm_value;
535}581}
536582
537static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {583static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
...@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -559,10 +605,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
559 unsigned flags = ZigLLVM_DIFlags_StaticMember;605 unsigned flags = ZigLLVM_DIFlags_StaticMember;
560 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);606 ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent);
561 assert(fn_di_scope != nullptr);607 assert(fn_di_scope != nullptr);
608 assert(fn_table_entry->raw_di_type != nullptr);
562 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,609 ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
563 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",610 fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
564 import->data.structure.root_struct->di_file, line_number,611 import->data.structure.root_struct->di_file, line_number,
565 fn_table_entry->type_entry->data.fn.raw_di_type, is_internal_linkage,612 fn_table_entry->raw_di_type, is_internal_linkage,
566 is_definition, scope_line, flags, is_optimized, nullptr);613 is_definition, scope_line, flags, is_optimized, nullptr);
567614
568 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);615 scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
...@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -597,7 +644,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
597 case ScopeIdLoop:644 case ScopeIdLoop:
598 case ScopeIdSuspend:645 case ScopeIdSuspend:
599 case ScopeIdCompTime:646 case ScopeIdCompTime:
600 case ScopeIdCoroPrelude:
601 case ScopeIdRuntime:647 case ScopeIdRuntime:
602 return get_di_scope(g, scope->parent);648 return get_di_scope(g, scope->parent);
603 }649 }
...@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {...@@ -798,9 +844,8 @@ static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
798 return false;844 return false;
799}845}
800846
801static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {847static bool ir_want_runtime_safety_scope(CodeGen *g, Scope *scope) {
802 // TODO memoize848 // TODO memoize
803 Scope *scope = instruction->scope;
804 while (scope) {849 while (scope) {
805 if (scope->id == ScopeIdBlock) {850 if (scope->id == ScopeIdBlock) {
806 ScopeBlock *block_scope = (ScopeBlock *)scope;851 ScopeBlock *block_scope = (ScopeBlock *)scope;
...@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {...@@ -818,6 +863,10 @@ static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
818 g->build_mode != BuildModeSmallRelease);863 g->build_mode != BuildModeSmallRelease);
819}864}
820865
866static bool ir_want_runtime_safety(CodeGen *g, IrInstruction *instruction) {
867 return ir_want_runtime_safety_scope(g, instruction->scope);
868}
869
821static Buf *panic_msg_buf(PanicMsgId msg_id) {870static Buf *panic_msg_buf(PanicMsgId msg_id) {
822 switch (msg_id) {871 switch (msg_id) {
823 case PanicMsgIdCount:872 case PanicMsgIdCount:
...@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -858,6 +907,18 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
858 return buf_create_from_str("integer part of floating point value out of bounds");907 return buf_create_from_str("integer part of floating point value out of bounds");
859 case PanicMsgIdPtrCastNull:908 case PanicMsgIdPtrCastNull:
860 return buf_create_from_str("cast causes pointer to be null");909 return buf_create_from_str("cast causes pointer to be null");
910 case PanicMsgIdBadResume:
911 return buf_create_from_str("resumed an async function which already returned");
912 case PanicMsgIdBadAwait:
913 return buf_create_from_str("async function awaited twice");
914 case PanicMsgIdBadReturn:
915 return buf_create_from_str("async function returned twice");
916 case PanicMsgIdResumedAnAwaitingFn:
917 return buf_create_from_str("awaiting function resumed");
918 case PanicMsgIdFrameTooSmall:
919 return buf_create_from_str("frame too small");
920 case PanicMsgIdResumedFnPendingAwait:
921 return buf_create_from_str("resumed an async function which can only be awaited");
861 }922 }
862 zig_unreachable();923 zig_unreachable();
863}924}
...@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -882,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
882 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));943 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0));
883}944}
884945
946static ZigType *ptr_to_stack_trace_type(CodeGen *g) {
947 return get_pointer_to_type(g, get_stack_trace_type(g), false);
948}
949
885static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {950static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
886 assert(g->panic_fn != nullptr);951 assert(g->panic_fn != nullptr);
887 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);952 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
888 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);953 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
889 if (stack_trace_arg == nullptr) {954 if (stack_trace_arg == nullptr) {
890 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);955 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
891 stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
892 }956 }
893 LLVMValueRef args[] = {957 LLVMValueRef args[] = {
894 msg_arg,958 msg_arg,
...@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {...@@ -904,14 +968,18 @@ static void gen_safety_crash(CodeGen *g, PanicMsgId msg_id) {
904 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);968 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
905}969}
906970
907static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {971static void gen_assertion_scope(CodeGen *g, PanicMsgId msg_id, Scope *source_scope) {
908 if (ir_want_runtime_safety(g, source_instruction)) {972 if (ir_want_runtime_safety_scope(g, source_scope)) {
909 gen_safety_crash(g, msg_id);973 gen_safety_crash(g, msg_id);
910 } else {974 } else {
911 LLVMBuildUnreachable(g->builder);975 LLVMBuildUnreachable(g->builder);
912 }976 }
913}977}
914978
979static void gen_assertion(CodeGen *g, PanicMsgId msg_id, IrInstruction *source_instruction) {
980 return gen_assertion_scope(g, msg_id, source_instruction->scope);
981}
982
915static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {983static LLVMValueRef get_stacksave_fn_val(CodeGen *g) {
916 if (g->stacksave_fn_val)984 if (g->stacksave_fn_val)
917 return g->stacksave_fn_val;985 return g->stacksave_fn_val;
...@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {...@@ -959,177 +1027,6 @@ static LLVMValueRef get_write_register_fn_val(CodeGen *g) {
959 return g->write_register_fn_val;1027 return g->write_register_fn_val;
960}1028}
9611029
962static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
963 if (g->coro_destroy_fn_val)
964 return g->coro_destroy_fn_val;
965
966 LLVMTypeRef param_types[] = {
967 LLVMPointerType(LLVMInt8Type(), 0),
968 };
969 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
970 Buf *name = buf_sprintf("llvm.coro.destroy");
971 g->coro_destroy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
972 assert(LLVMGetIntrinsicID(g->coro_destroy_fn_val));
973
974 return g->coro_destroy_fn_val;
975}
976
977static LLVMValueRef get_coro_id_fn_val(CodeGen *g) {
978 if (g->coro_id_fn_val)
979 return g->coro_id_fn_val;
980
981 LLVMTypeRef param_types[] = {
982 LLVMInt32Type(),
983 LLVMPointerType(LLVMInt8Type(), 0),
984 LLVMPointerType(LLVMInt8Type(), 0),
985 LLVMPointerType(LLVMInt8Type(), 0),
986 };
987 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 4, false);
988 Buf *name = buf_sprintf("llvm.coro.id");
989 g->coro_id_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
990 assert(LLVMGetIntrinsicID(g->coro_id_fn_val));
991
992 return g->coro_id_fn_val;
993}
994
995static LLVMValueRef get_coro_alloc_fn_val(CodeGen *g) {
996 if (g->coro_alloc_fn_val)
997 return g->coro_alloc_fn_val;
998
999 LLVMTypeRef param_types[] = {
1000 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1001 };
1002 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 1, false);
1003 Buf *name = buf_sprintf("llvm.coro.alloc");
1004 g->coro_alloc_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1005 assert(LLVMGetIntrinsicID(g->coro_alloc_fn_val));
1006
1007 return g->coro_alloc_fn_val;
1008}
1009
1010static LLVMValueRef get_coro_size_fn_val(CodeGen *g) {
1011 if (g->coro_size_fn_val)
1012 return g->coro_size_fn_val;
1013
1014 LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->llvm_type, nullptr, 0, false);
1015 Buf *name = buf_sprintf("llvm.coro.size.i%d", g->pointer_size_bytes * 8);
1016 g->coro_size_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1017 assert(LLVMGetIntrinsicID(g->coro_size_fn_val));
1018
1019 return g->coro_size_fn_val;
1020}
1021
1022static LLVMValueRef get_coro_begin_fn_val(CodeGen *g) {
1023 if (g->coro_begin_fn_val)
1024 return g->coro_begin_fn_val;
1025
1026 LLVMTypeRef param_types[] = {
1027 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1028 LLVMPointerType(LLVMInt8Type(), 0),
1029 };
1030 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1031 Buf *name = buf_sprintf("llvm.coro.begin");
1032 g->coro_begin_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1033 assert(LLVMGetIntrinsicID(g->coro_begin_fn_val));
1034
1035 return g->coro_begin_fn_val;
1036}
1037
1038static LLVMValueRef get_coro_suspend_fn_val(CodeGen *g) {
1039 if (g->coro_suspend_fn_val)
1040 return g->coro_suspend_fn_val;
1041
1042 LLVMTypeRef param_types[] = {
1043 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1044 LLVMInt1Type(),
1045 };
1046 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt8Type(), param_types, 2, false);
1047 Buf *name = buf_sprintf("llvm.coro.suspend");
1048 g->coro_suspend_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1049 assert(LLVMGetIntrinsicID(g->coro_suspend_fn_val));
1050
1051 return g->coro_suspend_fn_val;
1052}
1053
1054static LLVMValueRef get_coro_end_fn_val(CodeGen *g) {
1055 if (g->coro_end_fn_val)
1056 return g->coro_end_fn_val;
1057
1058 LLVMTypeRef param_types[] = {
1059 LLVMPointerType(LLVMInt8Type(), 0),
1060 LLVMInt1Type(),
1061 };
1062 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 2, false);
1063 Buf *name = buf_sprintf("llvm.coro.end");
1064 g->coro_end_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1065 assert(LLVMGetIntrinsicID(g->coro_end_fn_val));
1066
1067 return g->coro_end_fn_val;
1068}
1069
1070static LLVMValueRef get_coro_free_fn_val(CodeGen *g) {
1071 if (g->coro_free_fn_val)
1072 return g->coro_free_fn_val;
1073
1074 LLVMTypeRef param_types[] = {
1075 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1076 LLVMPointerType(LLVMInt8Type(), 0),
1077 };
1078 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1079 Buf *name = buf_sprintf("llvm.coro.free");
1080 g->coro_free_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1081 assert(LLVMGetIntrinsicID(g->coro_free_fn_val));
1082
1083 return g->coro_free_fn_val;
1084}
1085
1086static LLVMValueRef get_coro_resume_fn_val(CodeGen *g) {
1087 if (g->coro_resume_fn_val)
1088 return g->coro_resume_fn_val;
1089
1090 LLVMTypeRef param_types[] = {
1091 LLVMPointerType(LLVMInt8Type(), 0),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
1094 Buf *name = buf_sprintf("llvm.coro.resume");
1095 g->coro_resume_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_resume_fn_val));
1097
1098 return g->coro_resume_fn_val;
1099}
1100
1101static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
1102 if (g->coro_save_fn_val)
1103 return g->coro_save_fn_val;
1104
1105 LLVMTypeRef param_types[] = {
1106 LLVMPointerType(LLVMInt8Type(), 0),
1107 };
1108 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 1, false);
1109 Buf *name = buf_sprintf("llvm.coro.save");
1110 g->coro_save_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1111 assert(LLVMGetIntrinsicID(g->coro_save_fn_val));
1112
1113 return g->coro_save_fn_val;
1114}
1115
1116static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1117 if (g->coro_promise_fn_val)
1118 return g->coro_promise_fn_val;
1119
1120 LLVMTypeRef param_types[] = {
1121 LLVMPointerType(LLVMInt8Type(), 0),
1122 LLVMInt32Type(),
1123 LLVMInt1Type(),
1124 };
1125 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1126 Buf *name = buf_sprintf("llvm.coro.promise");
1127 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1128 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1129
1130 return g->coro_promise_fn_val;
1131}
1132
1133static LLVMValueRef get_return_address_fn_val(CodeGen *g) {1030static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1134 if (g->return_address_fn_val)1031 if (g->return_address_fn_val)
1135 return g->return_address_fn_val;1032 return g->return_address_fn_val;
...@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1149,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1149 return g->add_error_return_trace_addr_fn_val;1046 return g->add_error_return_trace_addr_fn_val;
11501047
1151 LLVMTypeRef arg_types[] = {1048 LLVMTypeRef arg_types[] = {
1152 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),1049 get_llvm_type(g, ptr_to_stack_trace_type(g)),
1153 g->builtin_types.entry_usize->llvm_type,1050 g->builtin_types.entry_usize->llvm_type,
1154 };1051 };
1155 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);1052 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
...@@ -1164,7 +1061,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1164,7 +1061,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1164 // Error return trace memory is in the stack, which is impossible to be at address 01061 // Error return trace memory is in the stack, which is impossible to be at address 0
1165 // on any architecture.1062 // on any architecture.
1166 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");1063 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1167 if (g->build_mode == BuildModeDebug) {1064 if (codegen_have_frame_pointer(g)) {
1168 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1065 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1169 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1066 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1170 }1067 }
...@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {...@@ -1222,140 +1119,6 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1222 return fn_val;1119 return fn_val;
1223}1120}
12241121
1225static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1226 if (g->merge_err_ret_traces_fn_val)
1227 return g->merge_err_ret_traces_fn_val;
1228
1229 assert(g->stack_trace_type != nullptr);
1230
1231 LLVMTypeRef param_types[] = {
1232 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1233 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),
1234 };
1235 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1236
1237 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1238 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1239 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1240 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1241 addLLVMFnAttr(fn_val, "nounwind");
1242 add_uwtable_attr(g, fn_val);
1243 // Error return trace memory is in the stack, which is impossible to be at address 0
1244 // on any architecture.
1245 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1246 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1247 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1248 // Error return trace memory is in the stack, which is impossible to be at address 0
1249 // on any architecture.
1250 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1251 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1252 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1253 if (g->build_mode == BuildModeDebug) {
1254 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1255 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1256 }
1257
1258 // this is above the ZigLLVMClearCurrentDebugLocation
1259 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1260
1261 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1262 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1263 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1264 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1265 ZigLLVMClearCurrentDebugLocation(g->builder);
1266
1267 // var frame_index: usize = undefined;
1268 // var frames_left: usize = undefined;
1269 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1270 // frame_index = 0;
1271 // frames_left = src_stack_trace.index;
1272 // if (frames_left == 0) return;
1273 // } else {
1274 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1275 // frames_left = src_stack_trace.instruction_addresses.len;
1276 // }
1277 // while (true) {
1278 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1279 // frames_left -= 1;
1280 // if (frames_left == 0) return;
1281 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1282 // }
1283 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1284
1285 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
1286 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
1287
1288 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1289 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1290
1291 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1292 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1293 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1294 (unsigned)src_index_field_index, "");
1295 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1296 (unsigned)src_addresses_field_index, "");
1297 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1298 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1299 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1300 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1301 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1302 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1303 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1304 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1305 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1306 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1307 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1308 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1309 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1310
1311 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1312 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
1313 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1314 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1315 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1316 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1317
1318 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1319 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
1320 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1321 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1322 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1323 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1324 LLVMBuildBr(g->builder, loop_block);
1325
1326 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1327 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1328 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1329 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1330 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1331 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1332 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1333 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1334 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1335 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1336 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1337
1338 LLVMPositionBuilderAtEnd(g->builder, return_block);
1339 LLVMBuildRetVoid(g->builder);
1340
1341 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1342 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1343 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1344 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1345 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1346 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1347 LLVMBuildBr(g->builder, loop_block);
1348
1349 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1350 if (!g->strip_debug_symbols) {
1351 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1352 }
1353
1354 g->merge_err_ret_traces_fn_val = fn_val;
1355 return fn_val;
1356
1357}
1358
1359static LLVMValueRef get_return_err_fn(CodeGen *g) {1122static LLVMValueRef get_return_err_fn(CodeGen *g) {
1360 if (g->return_err_fn != nullptr)1123 if (g->return_err_fn != nullptr)
1361 return g->return_err_fn;1124 return g->return_err_fn;
...@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1364,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
13641127
1365 LLVMTypeRef arg_types[] = {1128 LLVMTypeRef arg_types[] = {
1366 // error return trace pointer1129 // error return trace pointer
1367 get_llvm_type(g, get_ptr_to_stack_trace_type(g)),1130 get_llvm_type(g, ptr_to_stack_trace_type(g)),
1368 };1131 };
1369 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1132 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
13701133
...@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1376,10 +1139,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1376 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1139 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1377 addLLVMFnAttr(fn_val, "nounwind");1140 addLLVMFnAttr(fn_val, "nounwind");
1378 add_uwtable_attr(g, fn_val);1141 add_uwtable_attr(g, fn_val);
1379 // Error return trace memory is in the stack, which is impossible to be at address 01142 if (codegen_have_frame_pointer(g)) {
1380 // on any architecture.
1381 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1382 if (g->build_mode == BuildModeDebug) {
1383 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1143 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1384 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1144 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1385 }1145 }
...@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1400,6 +1160,17 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1400 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");1160 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1401 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");1161 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
14021162
1163 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1164 LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull");
1165
1166 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_ret_trace_ptr,
1167 LLVMConstNull(LLVMTypeOf(err_ret_trace_ptr)), "");
1168 LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block);
1169
1170 LLVMPositionBuilderAtEnd(g->builder, return_block);
1171 LLVMBuildRetVoid(g->builder);
1172
1173 LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block);
1403 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };1174 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1404 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");1175 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1405 LLVMBuildRetVoid(g->builder);1176 LLVMBuildRetVoid(g->builder);
...@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1434,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1434 LLVMTypeRef fn_type_ref;1205 LLVMTypeRef fn_type_ref;
1435 if (g->have_err_ret_tracing) {1206 if (g->have_err_ret_tracing) {
1436 LLVMTypeRef arg_types[] = {1207 LLVMTypeRef arg_types[] = {
1437 get_llvm_type(g, g->ptr_to_stack_trace_type),1208 get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)),
1438 get_llvm_type(g, g->err_tag_type),1209 get_llvm_type(g, g->err_tag_type),
1439 };1210 };
1440 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);1211 fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
...@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1451,7 +1222,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1451 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1222 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1452 addLLVMFnAttr(fn_val, "nounwind");1223 addLLVMFnAttr(fn_val, "nounwind");
1453 add_uwtable_attr(g, fn_val);1224 add_uwtable_attr(g, fn_val);
1454 if (g->build_mode == BuildModeDebug) {1225 if (codegen_have_frame_pointer(g)) {
1455 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");1226 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1456 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);1227 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1457 }1228 }
...@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1543,25 +1314,10 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1543 return fn_val;1314 return fn_val;
1544}1315}
15451316
1546static bool is_coro_prelude_scope(Scope *scope) {
1547 while (scope != nullptr) {
1548 if (scope->id == ScopeIdCoroPrelude) {
1549 return true;
1550 } else if (scope->id == ScopeIdFnDef) {
1551 break;
1552 }
1553 scope = scope->parent;
1554 }
1555 return false;
1556}
1557
1558static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {1317static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) {
1559 if (!g->have_err_ret_tracing) {1318 if (!g->have_err_ret_tracing) {
1560 return nullptr;1319 return nullptr;
1561 }1320 }
1562 if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
1563 return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack;
1564 }
1565 if (g->cur_err_ret_trace_val_stack != nullptr) {1321 if (g->cur_err_ret_trace_val_stack != nullptr) {
1566 return g->cur_err_ret_trace_val_stack;1322 return g->cur_err_ret_trace_val_stack;
1567 }1323 }
...@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc...@@ -1574,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc
1574 if (g->have_err_ret_tracing) {1330 if (g->have_err_ret_tracing) {
1575 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);1331 LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope);
1576 if (err_ret_trace_val == nullptr) {1332 if (err_ret_trace_val == nullptr) {
1577 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);1333 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
1578 err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
1579 }1334 }
1580 LLVMValueRef args[] = {1335 LLVMValueRef args[] = {
1581 err_ret_trace_val,1336 err_ret_trace_val,
...@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {...@@ -1820,14 +1575,14 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
1820 }1575 }
1821}1576}
18221577
1823static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,1578static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type,
1824 LLVMValueRef value)1579 LLVMValueRef value)
1825{1580{
1826 assert(ptr_type->id == ZigTypeIdPointer);1581 assert(ptr_type->id == ZigTypeIdPointer);
1827 ZigType *child_type = ptr_type->data.pointer.child_type;1582 ZigType *child_type = ptr_type->data.pointer.child_type;
18281583
1829 if (!type_has_bits(child_type))1584 if (!type_has_bits(child_type))
1830 return nullptr;1585 return;
18311586
1832 if (handle_is_ptr(child_type)) {1587 if (handle_is_ptr(child_type)) {
1833 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);1588 assert(LLVMGetTypeKind(LLVMTypeOf(value)) == LLVMPointerTypeKind);
...@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty...@@ -1847,13 +1602,13 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
1847 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,1602 ZigLLVMBuildMemCpy(g->builder, dest_ptr, align_bytes, src_ptr, align_bytes,
1848 LLVMConstInt(usize->llvm_type, size_bytes, false),1603 LLVMConstInt(usize->llvm_type, size_bytes, false),
1849 ptr_type->data.pointer.is_volatile);1604 ptr_type->data.pointer.is_volatile);
1850 return nullptr;1605 return;
1851 }1606 }
18521607
1853 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;1608 uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
1854 if (host_int_bytes == 0) {1609 if (host_int_bytes == 0) {
1855 gen_store(g, value, ptr, ptr_type);1610 gen_store(g, value, ptr, ptr_type);
1856 return nullptr;1611 return;
1857 }1612 }
18581613
1859 bool big_endian = g->is_big_endian;1614 bool big_endian = g->is_big_endian;
...@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty...@@ -1883,7 +1638,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
1883 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");1638 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
18841639
1885 gen_store(g, ored_value, ptr, ptr_type);1640 gen_store(g, ored_value, ptr, ptr_type);
1886 return nullptr;1641 return;
1887}1642}
18881643
1889static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {1644static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
...@@ -1967,7 +1722,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_...@@ -1967,7 +1722,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
1967 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];1722 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1968 ty = param_info->type;1723 ty = param_info->type;
1969 source_node = fn_walk->data.attrs.fn->proto_node;1724 source_node = fn_walk->data.attrs.fn->proto_node;
1970 llvm_fn = fn_walk->data.attrs.fn->llvm_value;1725 llvm_fn = fn_walk->data.attrs.llvm_fn;
1971 break;1726 break;
1972 case FnWalkIdCall: {1727 case FnWalkIdCall: {
1973 if (src_i >= fn_walk->data.call.inst->arg_count)1728 if (src_i >= fn_walk->data.call.inst->arg_count)
...@@ -2149,10 +1904,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_...@@ -2149,10 +1904,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
2149 }1904 }
2150 case FnWalkIdInits: {1905 case FnWalkIdInits: {
2151 clear_debug_source_node(g);1906 clear_debug_source_node(g);
2152 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);1907 if (!fn_is_async(fn_walk->data.inits.fn)) {
2153 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);1908 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2154 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");1909 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2155 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);1910 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
1911 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1912 }
2156 if (var->decl_node) {1913 if (var->decl_node) {
2157 gen_var_debug_decl(g, var);1914 gen_var_debug_decl(g, var);
2158 }1915 }
...@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2201,6 +1958,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2201 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);1958 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
2202 assert(param_value);1959 assert(param_value);
2203 fn_walk->data.call.gen_param_values->append(param_value);1960 fn_walk->data.call.gen_param_values->append(param_value);
1961 fn_walk->data.call.gen_param_types->append(param_type);
2204 }1962 }
2205 }1963 }
2206 return;1964 return;
...@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2216,7 +1974,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
22161974
2217 switch (fn_walk->id) {1975 switch (fn_walk->id) {
2218 case FnWalkIdAttrs: {1976 case FnWalkIdAttrs: {
2219 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;1977 LLVMValueRef llvm_fn = fn_walk->data.attrs.llvm_fn;
2220 bool is_byval = gen_info->is_byval;1978 bool is_byval = gen_info->is_byval;
2221 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];1979 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
22221980
...@@ -2245,7 +2003,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2245,7 +2003,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2245 assert(variable);2003 assert(variable);
2246 assert(variable->value_ref);2004 assert(variable->value_ref);
22472005
2248 if (!handle_is_ptr(variable->var_type)) {2006 if (!handle_is_ptr(variable->var_type) && !fn_is_async(fn_walk->data.inits.fn)) {
2249 clear_debug_source_node(g);2007 clear_debug_source_node(g);
2250 ZigType *fn_type = fn_table_entry->type_entry;2008 ZigType *fn_type = fn_table_entry->type_entry;
2251 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;2009 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;
...@@ -2271,48 +2029,357 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2271,48 +2029,357 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2271 }2029 }
2272}2030}
22732031
2032static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
2033 if (g->merge_err_ret_traces_fn_val)
2034 return g->merge_err_ret_traces_fn_val;
2035
2036 assert(g->stack_trace_type != nullptr);
2037
2038 LLVMTypeRef param_types[] = {
2039 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2040 get_llvm_type(g, ptr_to_stack_trace_type(g)),
2041 };
2042 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
2043
2044 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
2045 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
2046 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
2047 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
2048 addLLVMFnAttr(fn_val, "nounwind");
2049 add_uwtable_attr(g, fn_val);
2050 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
2051 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
2052
2053 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
2054 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
2055 if (g->build_mode == BuildModeDebug) {
2056 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
2057 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
2058 }
2059
2060 // this is above the ZigLLVMClearCurrentDebugLocation
2061 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
2062
2063 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
2064 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
2065 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
2066 LLVMPositionBuilderAtEnd(g->builder, entry_block);
2067 ZigLLVMClearCurrentDebugLocation(g->builder);
2068
2069 // if (dest_stack_trace == null or src_stack_trace == null) return;
2070 // var frame_index: usize = undefined;
2071 // var frames_left: usize = undefined;
2072 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
2073 // frame_index = 0;
2074 // frames_left = src_stack_trace.index;
2075 // if (frames_left == 0) return;
2076 // } else {
2077 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
2078 // frames_left = src_stack_trace.instruction_addresses.len;
2079 // }
2080 // while (true) {
2081 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
2082 // frames_left -= 1;
2083 // if (frames_left == 0) return;
2084 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
2085 // }
2086 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
2087 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull");
2088
2089 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index");
2090 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left");
2091
2092 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
2093 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
2094
2095 LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr,
2096 LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), "");
2097 LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr,
2098 LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), "");
2099 LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, "");
2100 LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block);
2101
2102 LLVMPositionBuilderAtEnd(g->builder, non_null_block);
2103 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
2104 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
2105 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2106 (unsigned)src_index_field_index, "");
2107 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
2108 (unsigned)src_addresses_field_index, "");
2109 ZigType *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
2110 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
2111 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
2112 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
2113 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
2114 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
2115 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
2116 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
2117 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
2118 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
2119 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
2120 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
2121 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
2122
2123 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
2124 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type);
2125 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
2126 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
2127 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
2128 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
2129
2130 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
2131 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
2132 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
2133 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
2134 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
2135 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
2136 LLVMBuildBr(g->builder, loop_block);
2137
2138 LLVMPositionBuilderAtEnd(g->builder, loop_block);
2139 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2140 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
2141 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
2142 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
2143 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
2144 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
2145 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
2146 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
2147 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
2148 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
2149
2150 LLVMPositionBuilderAtEnd(g->builder, return_block);
2151 LLVMBuildRetVoid(g->builder);
2152
2153 LLVMPositionBuilderAtEnd(g->builder, continue_block);
2154 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
2155 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
2156 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
2157 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
2158 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
2159 LLVMBuildBr(g->builder, loop_block);
2160
2161 LLVMPositionBuilderAtEnd(g->builder, prev_block);
2162 if (!g->strip_debug_symbols) {
2163 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
2164 }
2165
2166 g->merge_err_ret_traces_fn_val = fn_val;
2167 return fn_val;
2168
2169}
2274static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,2170static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
2275 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)2171 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
2276{2172{
2277 assert(g->have_err_ret_tracing);2173 assert(g->have_err_ret_tracing);
22782174
2279 LLVMValueRef return_err_fn = get_return_err_fn(g);2175 LLVMValueRef return_err_fn = get_return_err_fn(g);
2280 LLVMValueRef args[] = {2176 LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope);
2281 get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope),2177 ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1,
2282 };
2283 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
2284 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");2178 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
2285 return call_instruction;2179
2180 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2181 if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) {
2182 LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
2183 frame_index_trace_arg(g, ret_type), "");
2184 LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr);
2185 }
2186
2187 return nullptr;
2188}
2189
2190static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, ResumeId resume_id, PanicMsgId msg_id,
2191 LLVMBasicBlockRef end_bb)
2192{
2193 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2194 LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
2195 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
2196 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
2197 LLVMConstInt(usize_type_ref, resume_id, false));
2198 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, "");
2199 LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block);
2200
2201 LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
2202 gen_assertion(g, msg_id, source_instr);
2203
2204 LLVMPositionBuilderAtEnd(g->builder, end_bb);
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;
2286}2228}
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
2289 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {2356 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
2290 if (return_instruction->value == nullptr) {2357 if (instruction->operand == nullptr) {
2291 LLVMBuildRetVoid(g->builder);2358 LLVMBuildRetVoid(g->builder);
2292 return nullptr;2359 return nullptr;
2293 }2360 }
2294 assert(g->cur_ret_ptr);2361 assert(g->cur_ret_ptr);
2295 src_assert(return_instruction->value->value.special != ConstValSpecialRuntime,2362 src_assert(instruction->operand->value.special != ConstValSpecialRuntime,
2296 return_instruction->base.source_node);2363 instruction->base.source_node);
2297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2364 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2298 ZigType *return_type = return_instruction->value->value.type;2365 ZigType *return_type = instruction->operand->value.type;
2299 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);2366 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
2300 LLVMBuildRetVoid(g->builder);2367 LLVMBuildRetVoid(g->builder);
2301 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&2368 } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync &&
2302 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))2369 handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type))
2303 {2370 {
2304 if (return_instruction->value == nullptr) {2371 if (instruction->operand == nullptr) {
2305 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");2372 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
2306 LLVMBuildRet(g->builder, by_val_value);2373 LLVMBuildRet(g->builder, by_val_value);
2307 } else {2374 } else {
2308 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2375 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2309 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");2376 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
2310 LLVMBuildRet(g->builder, by_val_value);2377 LLVMBuildRet(g->builder, by_val_value);
2311 }2378 }
2312 } else if (return_instruction->value == nullptr) {2379 } else if (instruction->operand == nullptr) {
2313 LLVMBuildRetVoid(g->builder);2380 LLVMBuildRetVoid(g->builder);
2314 } else {2381 } else {
2315 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);2382 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2316 LLVMBuildRet(g->builder, value);2383 LLVMBuildRet(g->builder, value);
2317 }2384 }
2318 return nullptr;2385 return nullptr;
...@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI...@@ -3242,14 +3309,17 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
3242 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");3309 return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
3243}3310}
32443311
3245static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {3312static void render_decl_var(CodeGen *g, ZigVar *var) {
3246 ZigVar *var = instruction->var;
3247
3248 if (!type_has_bits(var->var_type))3313 if (!type_has_bits(var->var_type))
3249 return nullptr;3314 return;
32503315
3251 var->value_ref = ir_llvm_value(g, instruction->var_ptr);3316 var->value_ref = ir_llvm_value(g, var->ptr_instruction);
3252 gen_var_debug_decl(g, var);3317 gen_var_debug_decl(g, var);
3318}
3319
3320static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
3321 instruction->var->ptr_instruction = instruction->var_ptr;
3322 render_decl_var(g, instruction->var);
3253 return nullptr;3323 return nullptr;
3254}3324}
32553325
...@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn...@@ -3467,8 +3537,9 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
3467static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,3537static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable,
3468 IrInstructionReturnPtr *instruction)3538 IrInstructionReturnPtr *instruction)
3469{3539{
3470 src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type),3540 if (!type_has_bits(instruction->base.value.type))
3471 instruction->base.source_node);3541 return nullptr;
3542 src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node);
3472 return g->cur_ret_ptr;3543 return g->cur_ret_ptr;
3473}3544}
34743545
...@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -3566,26 +3637,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
3566 }3637 }
3567}3638}
35683639
3569static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) {
3570 return g->have_err_ret_tracing &&
3571 (fn_type_id->return_type->id == ZigTypeIdErrorUnion ||
3572 fn_type_id->return_type->id == ZigTypeIdErrorSet ||
3573 fn_type_id->cc == CallingConventionAsync);
3574}
3575
3576static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3577 // 0 1 2 3
3578 // err_ret_stack allocator_ptr err_code other_args...
3579 return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0;
3580}
3581
3582static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
3583 // 0 1 2 3
3584 // err_ret_stack allocator_ptr err_code other_args...
3585 return 1 + get_async_allocator_arg_index(g, fn_type_id);
3586}
3587
3588
3589static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {3640static LLVMValueRef get_new_stack_addr(CodeGen *g, LLVMValueRef new_stack) {
3590 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");3641 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_ptr_index, "");
3591 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");3642 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, new_stack, (unsigned)slice_len_index, "");
...@@ -3623,16 +3674,124 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {...@@ -3623,16 +3674,124 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
3623 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);3674 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
3624}3675}
36253676
3677static void render_async_spills(CodeGen *g) {
3678 ZigType *fn_type = g->cur_fn->type_entry;
3679 ZigType *import = get_scope_import(&g->cur_fn->fndef_scope->base);
3680 uint32_t async_var_index = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
3681 for (size_t var_i = 0; var_i < g->cur_fn->variable_list.length; var_i += 1) {
3682 ZigVar *var = g->cur_fn->variable_list.at(var_i);
3683
3684 if (!type_has_bits(var->var_type)) {
3685 continue;
3686 }
3687 if (ir_get_var_is_comptime(var))
3688 continue;
3689 switch (type_requires_comptime(g, var->var_type)) {
3690 case ReqCompTimeInvalid:
3691 zig_unreachable();
3692 case ReqCompTimeYes:
3693 continue;
3694 case ReqCompTimeNo:
3695 break;
3696 }
3697 if (var->src_arg_index == SIZE_MAX) {
3698 continue;
3699 }
3700
3701 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index,
3702 buf_ptr(&var->name));
3703 async_var_index += 1;
3704 if (var->decl_node) {
3705 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
3706 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
3707 (unsigned)(var->decl_node->line + 1),
3708 get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
3709 gen_var_debug_decl(g, var);
3710 }
3711 }
3712
3713 ZigType *frame_type = g->cur_fn->frame_type->data.frame.locals_struct;
3714
3715 for (size_t alloca_i = 0; alloca_i < g->cur_fn->alloca_gen_list.length; alloca_i += 1) {
3716 IrInstructionAllocaGen *instruction = g->cur_fn->alloca_gen_list.at(alloca_i);
3717 if (instruction->field_index == SIZE_MAX)
3718 continue;
3719
3720 size_t gen_index = frame_type->data.structure.fields[instruction->field_index].gen_index;
3721 instruction->base.llvm_value = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, gen_index,
3722 instruction->name_hint);
3723 }
3724}
3725
3726static void render_async_var_decls(CodeGen *g, Scope *scope) {
3727 for (;;) {
3728 switch (scope->id) {
3729 case ScopeIdCImport:
3730 zig_unreachable();
3731 case ScopeIdFnDef:
3732 return;
3733 case ScopeIdVarDecl: {
3734 ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
3735 if (var->ptr_instruction != nullptr) {
3736 render_decl_var(g, var);
3737 }
3738 // fallthrough
3739 }
3740 case ScopeIdDecls:
3741 case ScopeIdBlock:
3742 case ScopeIdDefer:
3743 case ScopeIdDeferExpr:
3744 case ScopeIdLoop:
3745 case ScopeIdSuspend:
3746 case ScopeIdCompTime:
3747 case ScopeIdRuntime:
3748 scope = scope->parent;
3749 continue;
3750 }
3751 }
3752}
3753
3754static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
3755 LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
3756 LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
3757 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
3758 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
3759 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
3760 return LLVMBuildLoad(g->builder, prefix_ptr, "");
3761}
3762
3763static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
3764 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3765 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3766
3767 LLVMValueRef index_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 0, "");
3768 LLVMBuildStore(g->builder, zero, index_ptr);
3769
3770 LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 1, "");
3771 LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_ptr_index, "");
3772 LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) };
3773 LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP(g->builder, addrs_field_ptr, indices, 2, "");
3774 LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr);
3775
3776 LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_len_index, "");
3777 LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr);
3778}
3779
3626static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {3780static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3781 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3782
3627 LLVMValueRef fn_val;3783 LLVMValueRef fn_val;
3628 ZigType *fn_type;3784 ZigType *fn_type;
3785 bool callee_is_async;
3629 if (instruction->fn_entry) {3786 if (instruction->fn_entry) {
3630 fn_val = fn_llvm_value(g, instruction->fn_entry);3787 fn_val = fn_llvm_value(g, instruction->fn_entry);
3631 fn_type = instruction->fn_entry->type_entry;3788 fn_type = instruction->fn_entry->type_entry;
3789 callee_is_async = fn_is_async(instruction->fn_entry);
3632 } else {3790 } else {
3633 assert(instruction->fn_ref);3791 assert(instruction->fn_ref);
3634 fn_val = ir_llvm_value(g, instruction->fn_ref);3792 fn_val = ir_llvm_value(g, instruction->fn_ref);
3635 fn_type = instruction->fn_ref->value.type;3793 fn_type = instruction->fn_ref->value.type;
3794 callee_is_async = fn_type->data.fn.fn_type_id.cc == CallingConventionAsync;
3636 }3795 }
36373796
3638 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;3797 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
...@@ -3643,27 +3802,156 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3643,27 +3802,156 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3643 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;3802 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
36443803
3645 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);3804 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
3646 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);3805 bool prefix_arg_err_ret_stack = codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type);
3647 bool is_var_args = fn_type_id->is_var_args;3806 bool is_var_args = fn_type_id->is_var_args;
3648 ZigList<LLVMValueRef> gen_param_values = {};3807 ZigList<LLVMValueRef> gen_param_values = {};
3808 ZigList<ZigType *> gen_param_types = {};
3649 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;3809 LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr;
3650 if (first_arg_ret) {3810 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3651 gen_param_values.append(result_loc);3811 LLVMValueRef frame_result_loc;
3652 }3812 LLVMValueRef awaiter_init_val;
3653 if (prefix_arg_err_ret_stack) {3813 LLVMValueRef ret_ptr;
3654 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));3814 if (callee_is_async) {
3655 }3815 if (instruction->is_async) {
3656 if (instruction->is_async) {3816 if (instruction->new_stack == nullptr) {
3657 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));3817 awaiter_init_val = zero;
3818 frame_result_loc = result_loc;
3819
3820 if (ret_has_bits) {
3821 // Use the result location which is inside the frame if this is an async call.
3822 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
3823 }
3824 } else if (cc == CallingConventionAsync) {
3825 awaiter_init_val = zero;
3826 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3827 if (ir_want_runtime_safety(g, &instruction->base)) {
3828 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3829 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3830 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3831
3832 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3833 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3834
3835 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3836 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
3837
3838 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3839 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
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, "");3886 assert(frame_result_loc != nullptr);
3660 gen_param_values.append(err_val_ptr);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 }
3661 }3948 }
3662 FnWalk fn_walk = {};3949 FnWalk fn_walk = {};
3663 fn_walk.id = FnWalkIdCall;3950 fn_walk.id = FnWalkIdCall;
3664 fn_walk.data.call.inst = instruction;3951 fn_walk.data.call.inst = instruction;
3665 fn_walk.data.call.is_var_args = is_var_args;3952 fn_walk.data.call.is_var_args = is_var_args;
3666 fn_walk.data.call.gen_param_values = &gen_param_values;3953 fn_walk.data.call.gen_param_values = &gen_param_values;
3954 fn_walk.data.call.gen_param_types = &gen_param_types;
3667 walk_function_params(g, fn_type, &fn_walk);3955 walk_function_params(g, fn_type, &fn_walk);
36683956
3669 ZigLLVM_FnInline fn_inline;3957 ZigLLVM_FnInline fn_inline;
...@@ -3679,12 +3967,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3679,12 +3967,71 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3679 break;3967 break;
3680 }3968 }
36813969
3682 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);3970 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3683 LLVMValueRef result;3971 LLVMValueRef result;
36843972
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
3685 if (instruction->new_stack == nullptr) {4030 if (instruction->new_stack == nullptr) {
3686 result = ZigLLVMBuildCall(g->builder, fn_val,4031 result = ZigLLVMBuildCall(g->builder, fn_val,
3687 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");4032 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");
3688 } else {4035 } else {
3689 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);4036 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
3690 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);4037 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
...@@ -3697,13 +4044,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3697,13 +4044,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3697 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");4044 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
3698 }4045 }
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
3707 if (src_return_type->id == ZigTypeIdUnreachable) {4047 if (src_return_type->id == ZigTypeIdUnreachable) {
3708 return LLVMBuildUnreachable(g->builder);4048 return LLVMBuildUnreachable(g->builder);
3709 } else if (!ret_has_bits) {4049 } else if (!ret_has_bits) {
...@@ -4200,7 +4540,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {...@@ -4200,7 +4540,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
4200 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));4540 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
4201 addLLVMFnAttr(fn_val, "nounwind");4541 addLLVMFnAttr(fn_val, "nounwind");
4202 add_uwtable_attr(g, fn_val);4542 add_uwtable_attr(g, fn_val);
4203 if (g->build_mode == BuildModeDebug) {4543 if (codegen_have_frame_pointer(g)) {
4204 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");4544 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
4205 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);4545 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
4206 }4546 }
...@@ -4347,10 +4687,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -4347,10 +4687,6 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
4347 {4687 {
4348 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;4688 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
4349 ptr_val = target_val;4689 ptr_val = target_val;
4350 } else if (target_type->id == ZigTypeIdOptional &&
4351 target_type->data.maybe.child_type->id == ZigTypeIdPromise)
4352 {
4353 zig_panic("TODO audit this function");
4354 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {4690 } else if (target_type->id == ZigTypeIdStruct && target_type->data.structure.is_slice) {
4355 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;4691 ZigType *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
4356 align_bytes = get_ptr_align(g, slice_ptr_type);4692 align_bytes = get_ptr_align(g, slice_ptr_type);
...@@ -4388,26 +4724,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu...@@ -4388,26 +4724,11 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
4388{4724{
4389 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);4725 LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope);
4390 if (cur_err_ret_trace_val == nullptr) {4726 if (cur_err_ret_trace_val == nullptr) {
4391 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);4727 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g)));
4392 return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type));
4393 }4728 }
4394 return cur_err_ret_trace_val;4729 return cur_err_ret_trace_val;
4395}4730}
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
4411static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {4732static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
4412 switch (atomic_order) {4733 switch (atomic_order) {
4413 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;4734 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
...@@ -4722,24 +5043,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable...@@ -4722,24 +5043,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
4722 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");5043 return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
4723}5044}
47245045
4725static LLVMValueRef get_handle_fn_val(CodeGen *g) {5046static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable, IrInstructionFrameHandle *instruction) {
4726 if (g->coro_frame_fn_val)5047 return g->cur_frame_ptr;
4727 return g->coro_frame_fn_val;
4728
4729 LLVMTypeRef fn_type = LLVMFunctionType( LLVMPointerType(LLVMInt8Type(), 0)
4730 , nullptr, 0, false);
4731 Buf *name = buf_sprintf("llvm.coro.frame");
4732 g->coro_frame_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
4733 assert(LLVMGetIntrinsicID(g->coro_frame_fn_val));
4734
4735 return g->coro_frame_fn_val;
4736}
4737
4738static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
4739 IrInstructionHandle *instruction)
4740{
4741 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->builtin_types.entry_promise));
4742 return LLVMBuildCall(g->builder, get_handle_fn_val(g), &zero, 0, "");
4743}5048}
47445049
4745static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {5050static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
...@@ -5005,248 +5310,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst...@@ -5005,248 +5310,6 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
5005 return nullptr;5310 return nullptr;
5006}5311}
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
5250static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,5313static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
5251 IrInstructionAtomicRmw *instruction)5314 IrInstructionAtomicRmw *instruction)
5252{5315{
...@@ -5263,14 +5326,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -5263,14 +5326,15 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
5263 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);5326 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
52645327
5265 if (get_codegen_ptr_type(operand_type) == nullptr) {5328 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);
5267 }5330 }
52685331
5269 // it's a pointer but we need to treat it as an int5332 // it's a pointer but we need to treat it as an int
5270 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,5333 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
5271 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");5334 LLVMPointerType(g->builtin_types.entry_usize->llvm_type, 0), "");
5272 LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->llvm_type, "");5335 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);
5274 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");5338 return LLVMBuildIntToPtr(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
5275}5339}
52765340
...@@ -5284,27 +5348,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,...@@ -5284,27 +5348,6 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutable *executable,
5284 return load_inst;5348 return load_inst;
5285}5349}
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
5308static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {5351static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
5309 LLVMValueRef op = ir_llvm_value(g, instruction->op1);5352 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
5310 assert(instruction->base.value.type->id == ZigTypeIdFloat);5353 assert(instruction->base.value.type->id == ZigTypeIdFloat);
...@@ -5424,6 +5467,176 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab...@@ -5424,6 +5467,176 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
5424 return nullptr;5467 return nullptr;
5425}5468}
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
5427static void set_debug_location(CodeGen *g, IrInstruction *instruction) {5640static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
5428 AstNode *source_node = instruction->source_node;5641 AstNode *source_node = instruction->source_node;
5429 Scope *scope = instruction->scope;5642 Scope *scope = instruction->scope;
...@@ -5445,7 +5658,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5445,7 +5658,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5445 case IrInstructionIdSetRuntimeSafety:5658 case IrInstructionIdSetRuntimeSafety:
5446 case IrInstructionIdSetFloatMode:5659 case IrInstructionIdSetFloatMode:
5447 case IrInstructionIdArrayType:5660 case IrInstructionIdArrayType:
5448 case IrInstructionIdPromiseType:5661 case IrInstructionIdAnyFrameType:
5449 case IrInstructionIdSliceType:5662 case IrInstructionIdSliceType:
5450 case IrInstructionIdSizeOf:5663 case IrInstructionIdSizeOf:
5451 case IrInstructionIdSwitchTarget:5664 case IrInstructionIdSwitchTarget:
...@@ -5485,8 +5698,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5485,8 +5698,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5485 case IrInstructionIdTagType:5698 case IrInstructionIdTagType:
5486 case IrInstructionIdExport:5699 case IrInstructionIdExport:
5487 case IrInstructionIdErrorUnion:5700 case IrInstructionIdErrorUnion:
5488 case IrInstructionIdPromiseResultType:
5489 case IrInstructionIdAwaitBookkeeping:
5490 case IrInstructionIdAddImplicitReturnType:5701 case IrInstructionIdAddImplicitReturnType:
5491 case IrInstructionIdIntCast:5702 case IrInstructionIdIntCast:
5492 case IrInstructionIdFloatCast:5703 case IrInstructionIdFloatCast:
...@@ -5508,17 +5719,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5508,17 +5719,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5508 case IrInstructionIdCallSrc:5719 case IrInstructionIdCallSrc:
5509 case IrInstructionIdAllocaSrc:5720 case IrInstructionIdAllocaSrc:
5510 case IrInstructionIdEndExpr:5721 case IrInstructionIdEndExpr:
5511 case IrInstructionIdAllocaGen:
5512 case IrInstructionIdImplicitCast:5722 case IrInstructionIdImplicitCast:
5513 case IrInstructionIdResolveResult:5723 case IrInstructionIdResolveResult:
5514 case IrInstructionIdResetResult:5724 case IrInstructionIdResetResult:
5515 case IrInstructionIdResultPtr:
5516 case IrInstructionIdContainerInitList:5725 case IrInstructionIdContainerInitList:
5517 case IrInstructionIdSliceSrc:5726 case IrInstructionIdSliceSrc:
5518 case IrInstructionIdRef:5727 case IrInstructionIdRef:
5519 case IrInstructionIdBitCastSrc:5728 case IrInstructionIdBitCastSrc:
5520 case IrInstructionIdTestErrSrc:5729 case IrInstructionIdTestErrSrc:
5521 case IrInstructionIdUnionInitNamedField:5730 case IrInstructionIdUnionInitNamedField:
5731 case IrInstructionIdFrameType:
5732 case IrInstructionIdFrameSizeSrc:
5733 case IrInstructionIdAllocaGen:
5734 case IrInstructionIdAwaitSrc:
5522 zig_unreachable();5735 zig_unreachable();
55235736
5524 case IrInstructionIdDeclVarGen:5737 case IrInstructionIdDeclVarGen:
...@@ -5597,8 +5810,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5597,8 +5810,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5597 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);5810 return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
5598 case IrInstructionIdFrameAddress:5811 case IrInstructionIdFrameAddress:
5599 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);5812 return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
5600 case IrInstructionIdHandle:5813 case IrInstructionIdFrameHandle:
5601 return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);5814 return ir_render_handle(g, executable, (IrInstructionFrameHandle *)instruction);
5602 case IrInstructionIdOverflowOp:5815 case IrInstructionIdOverflowOp:
5603 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);5816 return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
5604 case IrInstructionIdTestErrGen:5817 case IrInstructionIdTestErrGen:
...@@ -5641,44 +5854,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5641,44 +5854,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5641 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);5854 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
5642 case IrInstructionIdErrorReturnTrace:5855 case IrInstructionIdErrorReturnTrace:
5643 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);5856 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
5644 case IrInstructionIdCancel:
5645 return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction);
5646 case IrInstructionIdGetImplicitAllocator:
5647 return ir_render_get_implicit_allocator(g, executable, (IrInstructionGetImplicitAllocator *)instruction);
5648 case IrInstructionIdCoroId:
5649 return ir_render_coro_id(g, executable, (IrInstructionCoroId *)instruction);
5650 case IrInstructionIdCoroAlloc:
5651 return ir_render_coro_alloc(g, executable, (IrInstructionCoroAlloc *)instruction);
5652 case IrInstructionIdCoroSize:
5653 return ir_render_coro_size(g, executable, (IrInstructionCoroSize *)instruction);
5654 case IrInstructionIdCoroBegin:
5655 return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);
5656 case IrInstructionIdCoroAllocFail:
5657 return ir_render_coro_alloc_fail(g, executable, (IrInstructionCoroAllocFail *)instruction);
5658 case IrInstructionIdCoroSuspend:
5659 return ir_render_coro_suspend(g, executable, (IrInstructionCoroSuspend *)instruction);
5660 case IrInstructionIdCoroEnd:
5661 return ir_render_coro_end(g, executable, (IrInstructionCoroEnd *)instruction);
5662 case IrInstructionIdCoroFree:
5663 return ir_render_coro_free(g, executable, (IrInstructionCoroFree *)instruction);
5664 case IrInstructionIdCoroResume:
5665 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
5666 case IrInstructionIdCoroSave:
5667 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
5668 case IrInstructionIdCoroPromise:
5669 return ir_render_coro_promise(g, executable, (IrInstructionCoroPromise *)instruction);
5670 case IrInstructionIdCoroAllocHelper:
5671 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
5672 case IrInstructionIdAtomicRmw:5857 case IrInstructionIdAtomicRmw:
5673 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);5858 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
5674 case IrInstructionIdAtomicLoad:5859 case IrInstructionIdAtomicLoad:
5675 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);5860 return ir_render_atomic_load(g, executable, (IrInstructionAtomicLoad *)instruction);
5676 case IrInstructionIdSaveErrRetAddr:5861 case IrInstructionIdSaveErrRetAddr:
5677 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);5862 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
5678 case IrInstructionIdMergeErrRetTraces:
5679 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
5680 case IrInstructionIdMarkErrRetTracePtr:
5681 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
5682 case IrInstructionIdFloatOp:5863 case IrInstructionIdFloatOp:
5683 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);5864 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
5684 case IrInstructionIdMulAdd:5865 case IrInstructionIdMulAdd:
...@@ -5695,6 +5876,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5695,6 +5876,20 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5695 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);5876 return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
5696 case IrInstructionIdPtrOfArrayToSlice:5877 case IrInstructionIdPtrOfArrayToSlice:
5697 return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction);5878 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);
5698 }5893 }
5699 zig_unreachable();5894 zig_unreachable();
5700}5895}
...@@ -5704,6 +5899,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {...@@ -5704,6 +5899,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
57045899
5705 IrExecutable *executable = &fn_entry->analyzed_executable;5900 IrExecutable *executable = &fn_entry->analyzed_executable;
5706 assert(executable->basic_block_list.length > 0);5901 assert(executable->basic_block_list.length > 0);
5902
5707 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {5903 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
5708 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);5904 IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
5709 assert(current_block->llvm_block);5905 assert(current_block->llvm_block);
...@@ -5894,7 +6090,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -5894,7 +6090,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5894 case ZigTypeIdPointer:6090 case ZigTypeIdPointer:
5895 case ZigTypeIdFn:6091 case ZigTypeIdFn:
5896 case ZigTypeIdOptional:6092 case ZigTypeIdOptional:
5897 case ZigTypeIdPromise:
5898 {6093 {
5899 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");6094 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
5900 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->llvm_type);6095 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...@@ -5957,7 +6152,10 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5957 }6152 }
5958 return val;6153 return val;
5959 }6154 }
59606155 case ZigTypeIdFnFrame:
6156 zig_panic("TODO bit pack an async function frame");
6157 case ZigTypeIdAnyFrame:
6158 zig_panic("TODO bit pack an anyframe");
5961 }6159 }
5962 zig_unreachable();6160 zig_unreachable();
5963}6161}
...@@ -6110,6 +6308,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6110,6 +6308,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6110 break;6308 break;
6111 }6309 }
61126310
6311 if ((err = type_resolve(g, type_entry, ResolveStatusLLVMFull)))
6312 zig_unreachable();
6313
6113 switch (type_entry->id) {6314 switch (type_entry->id) {
6114 case ZigTypeIdInt:6315 case ZigTypeIdInt:
6115 return bigint_to_llvm_const(get_llvm_type(g, type_entry), &const_val->data.x_bigint);6316 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...@@ -6181,6 +6382,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6181 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);6382 LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
6182 size_t src_field_count = type_entry->data.structure.src_field_count;6383 size_t src_field_count = type_entry->data.structure.src_field_count;
6183 bool make_unnamed_struct = false;6384 bool make_unnamed_struct = false;
6385 assert(type_entry->data.structure.resolve_status == ResolveStatusLLVMFull);
6184 if (type_entry->data.structure.layout == ContainerLayoutPacked) {6386 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
6185 size_t src_field_index = 0;6387 size_t src_field_index = 0;
6186 while (src_field_index < src_field_count) {6388 while (src_field_index < src_field_count) {
...@@ -6250,6 +6452,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6250,6 +6452,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6250 LLVMValueRef val = gen_const_val(g, field_val, "");6452 LLVMValueRef val = gen_const_val(g, field_val, "");
6251 fields[type_struct_field->gen_index] = val;6453 fields[type_struct_field->gen_index] = val;
6252 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);6454 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 }
6253 }6471 }
6254 }6472 }
6255 if (make_unnamed_struct) {6473 if (make_unnamed_struct) {
...@@ -6437,30 +6655,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6437,30 +6655,18 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6437 err_payload_value = gen_const_val(g, payload_val, "");6655 err_payload_value = gen_const_val(g, payload_val, "");
6438 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);6656 make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_val->type, err_payload_value);
6439 }6657 }
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 }
6440 if (make_unnamed_struct) {6666 if (make_unnamed_struct) {
6441 uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, get_llvm_type(g, type_entry), 1);6667 return LLVMConstStruct(fields, field_count, false);
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 }
6458 } else {6668 } else {
6459 LLVMValueRef fields[] = {6669 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, field_count);
6460 err_tag_value,
6461 err_payload_value,
6462 };
6463 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, 2);
6464 }6670 }
6465 }6671 }
6466 }6672 }
...@@ -6477,9 +6683,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -6477,9 +6683,11 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
6477 case ZigTypeIdBoundFn:6683 case ZigTypeIdBoundFn:
6478 case ZigTypeIdArgTuple:6684 case ZigTypeIdArgTuple:
6479 case ZigTypeIdOpaque:6685 case ZigTypeIdOpaque:
6480 case ZigTypeIdPromise:
6481 zig_unreachable();6686 zig_unreachable();
64826687 case ZigTypeIdFnFrame:
6688 zig_panic("TODO");
6689 case ZigTypeIdAnyFrame:
6690 zig_panic("TODO");
6483 }6691 }
6484 zig_unreachable();6692 zig_unreachable();
6485}6693}
...@@ -6563,12 +6771,20 @@ static void generate_error_name_table(CodeGen *g) {...@@ -6563,12 +6771,20 @@ static void generate_error_name_table(CodeGen *g) {
6563static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {6771static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) {
6564 IrExecutable *executable = &fn->analyzed_executable;6772 IrExecutable *executable = &fn->analyzed_executable;
6565 assert(executable->basic_block_list.length > 0);6773 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 }
6566 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {6780 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
6567 IrBasicBlock *bb = executable->basic_block_list.at(block_i);6781 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;
6569 }6786 }
6570 IrBasicBlock *entry_bb = executable->basic_block_list.at(0);6787 LLVMPositionBuilderAtEnd(g->builder, first_bb);
6571 LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
6572}6788}
65736789
6574static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,6790static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
...@@ -6745,13 +6961,19 @@ static void do_code_gen(CodeGen *g) {...@@ -6745,13 +6961,19 @@ static void do_code_gen(CodeGen *g) {
6745 build_all_basic_blocks(g, fn_table_entry);6961 build_all_basic_blocks(g, fn_table_entry);
6746 clear_debug_source_node(g);6962 clear_debug_source_node(g);
67476963
6748 if (want_sret) {6964 bool is_async = fn_is_async(fn_table_entry);
6749 g->cur_ret_ptr = LLVMGetParam(fn, 0);6965
6750 } else if (handle_is_ptr(fn_type_id->return_type)) {6966 if (is_async) {
6751 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);6967 g->cur_frame_ptr = LLVMGetParam(fn, 0);
6752 // TODO add debug info variable for this
6753 } else {6968 } 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 }
6755 }6977 }
67566978
6757 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);6979 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) {...@@ -6763,39 +6985,45 @@ static void do_code_gen(CodeGen *g) {
6763 }6985 }
67646986
6765 // error return tracing setup6987 // error return tracing setup
6766 bool is_async = cc == CallingConventionAsync;6988 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&
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;6989 !is_async && !have_err_ret_trace_arg;
6768 LLVMValueRef err_ret_array_val = nullptr;6990 LLVMValueRef err_ret_array_val = nullptr;
6769 if (have_err_ret_trace_stack) {6991 if (have_err_ret_trace_stack) {
6770 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);6992 ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
6771 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));6993 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_type6995 (void)get_llvm_type(g, get_stack_trace_type(g));
6774 (void)get_ptr_to_stack_trace_type(g);6996 g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace",
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));6997 get_abi_alignment(g, g->stack_trace_type));
6776 } else {6998 } else {
6777 g->cur_err_ret_trace_val_stack = nullptr;6999 g->cur_err_ret_trace_val_stack = nullptr;
6778 }7000 }
67797001
6780 // allocate temporary stack data7002 if (!is_async) {
6781 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {7003 // allocate temporary stack data
6782 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);7004 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6783 ZigType *ptr_type = instruction->base.value.type;7005 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6784 assert(ptr_type->id == ZigTypeIdPointer);7006 ZigType *ptr_type = instruction->base.value.type;
6785 ZigType *child_type = ptr_type->data.pointer.child_type;7007 assert(ptr_type->id == ZigTypeIdPointer);
6786 if (!type_has_bits(child_type))7008 ZigType *child_type = ptr_type->data.pointer.child_type;
6787 continue;7009 if (type_resolve(g, child_type, ResolveStatusSizeKnown))
6788 if (instruction->base.ref_count == 0)7010 zig_unreachable();
6789 continue;7011 if (!type_has_bits(child_type))
6790 if (instruction->base.value.special != ConstValSpecialRuntime) {7012 continue;
6791 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=7013 if (instruction->base.ref_count == 0)
6792 ConstValSpecialRuntime)
6793 {
6794 continue;7014 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 }
6795 }7021 }
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));
6796 }7026 }
6797 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6798 get_ptr_align(g, ptr_type));
6799 }7027 }
68007028
6801 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);7029 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
...@@ -6833,7 +7061,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6833,7 +7061,7 @@ static void do_code_gen(CodeGen *g) {
6833 } else if (is_c_abi) {7061 } else if (is_c_abi) {
6834 fn_walk_var.data.vars.var = var;7062 fn_walk_var.data.vars.var = var;
6835 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);7063 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) {
6837 ZigType *gen_type;7065 ZigType *gen_type;
6838 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];7066 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
6839 assert(gen_info->gen_index != SIZE_MAX);7067 assert(gen_info->gen_index != SIZE_MAX);
...@@ -6884,14 +7112,76 @@ static void do_code_gen(CodeGen *g) {...@@ -6884,14 +7112,76 @@ static void do_code_gen(CodeGen *g) {
6884 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));7112 gen_store(g, LLVMConstInt(usize->llvm_type, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
6885 }7113 }
68867114
6887 // create debug variable declarations for parameters7115 if (is_async) {
6888 // rely on the first variables in the variable_list being parameters.7116 (void)get_llvm_type(g, fn_table_entry->frame_type);
6889 FnWalk fn_walk_init = {};7117 g->cur_resume_block_count = 0;
6890 fn_walk_init.id = FnWalkIdInits;7118
6891 fn_walk_init.data.inits.fn = fn_table_entry;7119 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
6892 fn_walk_init.data.inits.llvm_fn = fn;7120 LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
6893 fn_walk_init.data.inits.gen_i = gen_i_init;7121 ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
6894 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);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
6896 ir_render(g, fn_table_entry);7186 ir_render(g, fn_table_entry);
68977187
...@@ -6910,8 +7200,6 @@ static void do_code_gen(CodeGen *g) {...@@ -6910,8 +7200,6 @@ static void do_code_gen(CodeGen *g) {
6910 LLVMDumpModule(g->module);7200 LLVMDumpModule(g->module);
6911 }7201 }
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.
6915#ifndef NDEBUG7203#ifndef NDEBUG
6916 char *error = nullptr;7204 char *error = nullptr;
6917 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);7205 LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
...@@ -7180,16 +7468,8 @@ static void define_builtin_types(CodeGen *g) {...@@ -7180,16 +7468,8 @@ static void define_builtin_types(CodeGen *g) {
71807468
7181 g->primitive_type_table.put(&entry->name, entry);7469 g->primitive_type_table.put(&entry->name, entry);
7182 }7470 }
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 }
7190}7471}
71917472
7192
7193static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {7473static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {
7194 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);7474 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
7195 buf_init_from_str(&builtin_fn->name, name);7475 buf_init_from_str(&builtin_fn->name, name);
...@@ -7202,8 +7482,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char...@@ -7202,8 +7482,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
7202static void define_builtin_fns(CodeGen *g) {7482static void define_builtin_fns(CodeGen *g) {
7203 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);7483 create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
7204 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);7484 create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
7205 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
7206 create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
7207 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);7485 create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
7208 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);7486 create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
7209 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);7487 create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
...@@ -7279,13 +7557,13 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7279,13 +7557,13 @@ static void define_builtin_fns(CodeGen *g) {
7279 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);7557 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
7280 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);7558 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
7281 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);7559 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7282 //Needs library support on Windows7560 create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7283 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7284 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);7561 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
7285 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);7562 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
7286 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);7563 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
7287 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);7564 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
7288 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);7565 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
7566 create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
7289 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);7567 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
7290 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);7568 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
7291 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);7569 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
...@@ -7304,6 +7582,10 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7304,6 +7582,10 @@ static void define_builtin_fns(CodeGen *g) {
7304 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);7582 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
7305 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);7583 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
7306 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);7584 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);
7307}7589}
73087590
7309static const char *bool_to_str(bool b) {7591static const char *bool_to_str(bool b) {
...@@ -7615,7 +7897,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7615,7 +7897,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7615 " BoundFn: Fn,\n"7897 " BoundFn: Fn,\n"
7616 " ArgTuple: void,\n"7898 " ArgTuple: void,\n"
7617 " Opaque: void,\n"7899 " Opaque: void,\n"
7618 " Promise: Promise,\n"7900 " Frame: void,\n"
7901 " AnyFrame: AnyFrame,\n"
7619 " Vector: Vector,\n"7902 " Vector: Vector,\n"
7620 " EnumLiteral: void,\n"7903 " EnumLiteral: void,\n"
7621 "\n\n"7904 "\n\n"
...@@ -7728,11 +8011,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7728,11 +8011,10 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7728 " is_generic: bool,\n"8011 " is_generic: bool,\n"
7729 " is_var_args: bool,\n"8012 " is_var_args: bool,\n"
7730 " return_type: ?type,\n"8013 " return_type: ?type,\n"
7731 " async_allocator_type: ?type,\n"
7732 " args: []FnArg,\n"8014 " args: []FnArg,\n"
7733 " };\n"8015 " };\n"
7734 "\n"8016 "\n"
7735 " pub const Promise = struct {\n"8017 " pub const AnyFrame = struct {\n"
7736 " child: ?type,\n"8018 " child: ?type,\n"
7737 " };\n"8019 " };\n"
7738 "\n"8020 "\n"
...@@ -8297,15 +8579,17 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8297,15 +8579,17 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8297 }8579 }
82988580
8299 // According to Rich Felker libc headers are supposed to go before C language headers.8581 // 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
8300 for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {8587 for (size_t i = 0; i < g->libc_include_dir_len; i += 1) {
8301 Buf *include_dir = g->libc_include_dir_list[i];8588 Buf *include_dir = g->libc_include_dir_list[i];
8302 args.append("-isystem");8589 args.append("-isystem");
8303 args.append(buf_ptr(include_dir));8590 args.append(buf_ptr(include_dir));
8304 }8591 }
83058592
8306 args.append("-isystem");
8307 args.append(buf_ptr(g->zig_c_headers_dir));
8308
8309 if (g->zig_target->is_native) {8593 if (g->zig_target->is_native) {
8310 args.append("-march=native");8594 args.append("-march=native");
8311 } else {8595 } else {
...@@ -8336,6 +8620,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8336,6 +8620,12 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8336 args.append("-g");8620 args.append("-g");
8337 }8621 }
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
8339 switch (g->build_mode) {8629 switch (g->build_mode) {
8340 case BuildModeDebug:8630 case BuildModeDebug:
8341 // windows c runtime requires -D_DEBUG if using debug libraries8631 // 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...@@ -8348,7 +8638,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8348 } else {8638 } else {
8349 args.append("-fno-stack-protector");8639 args.append("-fno-stack-protector");
8350 }8640 }
8351 args.append("-fno-omit-frame-pointer");
8352 break;8641 break;
8353 case BuildModeSafeRelease:8642 case BuildModeSafeRelease:
8354 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather8643 // 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...@@ -8362,7 +8651,6 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8362 } else {8651 } else {
8363 args.append("-fno-stack-protector");8652 args.append("-fno-stack-protector");
8364 }8653 }
8365 args.append("-fomit-frame-pointer");
8366 break;8654 break;
8367 case BuildModeFastRelease:8655 case BuildModeFastRelease:
8368 args.append("-DNDEBUG");8656 args.append("-DNDEBUG");
...@@ -8373,13 +8661,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa...@@ -8373,13 +8661,11 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa
8373 // running in -O2 and thus the -O3 path has been tested less.8661 // running in -O2 and thus the -O3 path has been tested less.
8374 args.append("-O2");8662 args.append("-O2");
8375 args.append("-fno-stack-protector");8663 args.append("-fno-stack-protector");
8376 args.append("-fomit-frame-pointer");
8377 break;8664 break;
8378 case BuildModeSmallRelease:8665 case BuildModeSmallRelease:
8379 args.append("-DNDEBUG");8666 args.append("-DNDEBUG");
8380 args.append("-Os");8667 args.append("-Os");
8381 args.append("-fno-stack-protector");8668 args.append("-fno-stack-protector");
8382 args.append("-fomit-frame-pointer");
8383 break;8669 break;
8384 }8670 }
83858671
...@@ -8907,7 +9193,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e...@@ -8907,7 +9193,8 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
8907 case ZigTypeIdArgTuple:9193 case ZigTypeIdArgTuple:
8908 case ZigTypeIdErrorUnion:9194 case ZigTypeIdErrorUnion:
8909 case ZigTypeIdErrorSet:9195 case ZigTypeIdErrorSet:
8910 case ZigTypeIdPromise:9196 case ZigTypeIdFnFrame:
9197 case ZigTypeIdAnyFrame:
8911 zig_unreachable();9198 zig_unreachable();
8912 case ZigTypeIdVoid:9199 case ZigTypeIdVoid:
8913 case ZigTypeIdUnreachable:9200 case ZigTypeIdUnreachable:
...@@ -9091,7 +9378,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -9091,7 +9378,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
9091 case ZigTypeIdUndefined:9378 case ZigTypeIdUndefined:
9092 case ZigTypeIdNull:9379 case ZigTypeIdNull:
9093 case ZigTypeIdArgTuple:9380 case ZigTypeIdArgTuple:
9094 case ZigTypeIdPromise:9381 case ZigTypeIdFnFrame:
9382 case ZigTypeIdAnyFrame:
9095 zig_unreachable();9383 zig_unreachable();
9096 }9384 }
9097}9385}
...@@ -9258,9 +9546,11 @@ static void gen_h_file(CodeGen *g) {...@@ -9258,9 +9546,11 @@ static void gen_h_file(CodeGen *g) {
9258 case ZigTypeIdArgTuple:9546 case ZigTypeIdArgTuple:
9259 case ZigTypeIdOptional:9547 case ZigTypeIdOptional:
9260 case ZigTypeIdFn:9548 case ZigTypeIdFn:
9261 case ZigTypeIdPromise:
9262 case ZigTypeIdVector:9549 case ZigTypeIdVector:
9550 case ZigTypeIdFnFrame:
9551 case ZigTypeIdAnyFrame:
9263 zig_unreachable();9552 zig_unreachable();
9553
9264 case ZigTypeIdEnum:9554 case ZigTypeIdEnum:
9265 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {9555 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
9266 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));9556 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...@@ -9799,3 +10089,18 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
9799 return g;10089 return g;
9800}10090}
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);...@@ -61,5 +61,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g);
61TargetSubsystem detect_subsystem(CodeGen *g);61TargetSubsystem detect_subsystem(CodeGen *g);
6262
63void codegen_release_caches(CodeGen *codegen);63void codegen_release_caches(CodeGen *codegen);
64bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type);
65bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async);
6466
65#endif67#endif
src/ir.cpp+880-1712
...@@ -26,6 +26,7 @@ struct IrBuilder {...@@ -26,6 +26,7 @@ struct IrBuilder {
26 CodeGen *codegen;26 CodeGen *codegen;
27 IrExecutable *exec;27 IrExecutable *exec;
28 IrBasicBlock *current_basic_block;28 IrBasicBlock *current_basic_block;
29 AstNode *main_block_node;
29};30};
3031
31struct IrAnalyze {32struct IrAnalyze {
...@@ -99,7 +100,6 @@ struct ConstCastOnly {...@@ -99,7 +100,6 @@ struct ConstCastOnly {
99 ConstCastErrUnionErrSetMismatch *error_union_error_set;100 ConstCastErrUnionErrSetMismatch *error_union_error_set;
100 ConstCastTypeMismatch *type_mismatch;101 ConstCastTypeMismatch *type_mismatch;
101 ConstCastOnly *return_type;102 ConstCastOnly *return_type;
102 ConstCastOnly *async_allocator_type;
103 ConstCastOnly *null_wrap_ptr_child;103 ConstCastOnly *null_wrap_ptr_child;
104 ConstCastArg fn_arg;104 ConstCastArg fn_arg;
105 ConstCastArgNoAlias arg_no_alias;105 ConstCastArgNoAlias arg_no_alias;
...@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {...@@ -305,6 +305,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
305 case ZigTypeIdBoundFn:305 case ZigTypeIdBoundFn:
306 case ZigTypeIdErrorSet:306 case ZigTypeIdErrorSet:
307 case ZigTypeIdOpaque:307 case ZigTypeIdOpaque:
308 case ZigTypeIdAnyFrame:
308 return true;309 return true;
309 case ZigTypeIdFloat:310 case ZigTypeIdFloat:
310 return a->data.floating.bit_count == b->data.floating.bit_count;311 return a->data.floating.bit_count == b->data.floating.bit_count;
...@@ -319,8 +320,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {...@@ -319,8 +320,8 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
319 case ZigTypeIdUnion:320 case ZigTypeIdUnion:
320 case ZigTypeIdFn:321 case ZigTypeIdFn:
321 case ZigTypeIdArgTuple:322 case ZigTypeIdArgTuple:
322 case ZigTypeIdPromise:
323 case ZigTypeIdVector:323 case ZigTypeIdVector:
324 case ZigTypeIdFnFrame:
324 return false;325 return false;
325 }326 }
326 zig_unreachable();327 zig_unreachable();
...@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {...@@ -565,8 +566,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
565 return IrInstructionIdArrayType;566 return IrInstructionIdArrayType;
566}567}
567568
568static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseType *) {569static constexpr IrInstructionId ir_instruction_id(IrInstructionAnyFrameType *) {
569 return IrInstructionIdPromiseType;570 return IrInstructionIdAnyFrameType;
570}571}
571572
572static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {573static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
...@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)...@@ -761,8 +762,20 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
761 return IrInstructionIdFrameAddress;762 return IrInstructionIdFrameAddress;
762}763}
763764
764static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {765static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameHandle *) {
765 return IrInstructionIdHandle;766 return IrInstructionIdFrameHandle;
767}
768
769static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameType *) {
770 return IrInstructionIdFrameType;
771}
772
773static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeSrc *) {
774 return IrInstructionIdFrameSizeSrc;
775}
776
777static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameSizeGen *) {
778 return IrInstructionIdFrameSizeGen;
766}779}
767780
768static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {781static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
...@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {...@@ -933,10 +946,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) {
933 return IrInstructionIdResetResult;946 return IrInstructionIdResetResult;
934}947}
935948
936static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) {
937 return IrInstructionIdResultPtr;
938}
939
940static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {949static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
941 return IrInstructionIdPtrOfArrayToSlice;950 return IrInstructionIdPtrOfArrayToSlice;
942}951}
...@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {...@@ -961,62 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
961 return IrInstructionIdErrorUnion;970 return IrInstructionIdErrorUnion;
962}971}
963972
964static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) {
965 return IrInstructionIdCancel;
966}
967
968static constexpr IrInstructionId ir_instruction_id(IrInstructionGetImplicitAllocator *) {
969 return IrInstructionIdGetImplicitAllocator;
970}
971
972static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroId *) {
973 return IrInstructionIdCoroId;
974}
975
976static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAlloc *) {
977 return IrInstructionIdCoroAlloc;
978}
979
980static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSize *) {
981 return IrInstructionIdCoroSize;
982}
983
984static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroBegin *) {
985 return IrInstructionIdCoroBegin;
986}
987
988static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *) {
989 return IrInstructionIdCoroAllocFail;
990}
991
992static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) {
993 return IrInstructionIdCoroSuspend;
994}
995
996static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) {
997 return IrInstructionIdCoroEnd;
998}
999
1000static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) {
1001 return IrInstructionIdCoroFree;
1002}
1003
1004static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
1005 return IrInstructionIdCoroResume;
1006}
1007
1008static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
1009 return IrInstructionIdCoroSave;
1010}
1011
1012static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
1013 return IrInstructionIdCoroPromise;
1014}
1015
1016static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
1017 return IrInstructionIdCoroAllocHelper;
1018}
1019
1020static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {973static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
1021 return IrInstructionIdAtomicRmw;974 return IrInstructionIdAtomicRmw;
1022}975}
...@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {...@@ -1025,14 +978,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicLoad *) {
1025 return IrInstructionIdAtomicLoad;978 return IrInstructionIdAtomicLoad;
1026}979}
1027980
1028static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
1029 return IrInstructionIdPromiseResultType;
1030}
1031
1032static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping *) {
1033 return IrInstructionIdAwaitBookkeeping;
1034}
1035
1036static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {981static constexpr IrInstructionId ir_instruction_id(IrInstructionSaveErrRetAddr *) {
1037 return IrInstructionIdSaveErrRetAddr;982 return IrInstructionIdSaveErrRetAddr;
1038}983}
...@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur...@@ -1041,14 +986,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
1041 return IrInstructionIdAddImplicitReturnType;986 return IrInstructionIdAddImplicitReturnType;
1042}987}
1043988
1044static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
1045 return IrInstructionIdMergeErrRetTraces;
1046}
1047
1048static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
1049 return IrInstructionIdMarkErrRetTracePtr;
1050}
1051
1052static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {989static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1053 return IrInstructionIdFloatOp;990 return IrInstructionIdFloatOp;
1054}991}
...@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi...@@ -1097,6 +1034,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedFi
1097 return IrInstructionIdUnionInitNamedField;1034 return IrInstructionIdUnionInitNamedField;
1098}1035}
10991036
1037static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendBegin *) {
1038 return IrInstructionIdSuspendBegin;
1039}
1040
1041static constexpr IrInstructionId ir_instruction_id(IrInstructionSuspendFinish *) {
1042 return IrInstructionIdSuspendFinish;
1043}
1044
1045static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitSrc *) {
1046 return IrInstructionIdAwaitSrc;
1047}
1048
1049static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitGen *) {
1050 return IrInstructionIdAwaitGen;
1051}
1052
1053static constexpr IrInstructionId ir_instruction_id(IrInstructionResume *) {
1054 return IrInstructionIdResume;
1055}
1056
1057static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillBegin *) {
1058 return IrInstructionIdSpillBegin;
1059}
1060
1061static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
1062 return IrInstructionIdSpillEnd;
1063}
1064
1100template<typename T>1065template<typename T>
1101static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1066static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1102 T *special_instruction = allocate<T>(1);1067 T *special_instruction = allocate<T>(1);
...@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so...@@ -1149,14 +1114,14 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
1149}1114}
11501115
1151static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,1116static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node,
1152 IrInstruction *return_value)1117 IrInstruction *operand)
1153{1118{
1154 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);1119 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, scope, source_node);
1155 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;1120 return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
1156 return_instruction->base.value.special = ConstValSpecialStatic;1121 return_instruction->base.value.special = ConstValSpecialStatic;
1157 return_instruction->value = return_value;1122 return_instruction->operand = operand;
11581123
1159 if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block);1124 if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block);
11601125
1161 return &return_instruction->base;1126 return &return_instruction->base;
1162}1127}
...@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode...@@ -1214,14 +1179,6 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode
1214 return &const_instruction->base;1179 return &const_instruction->base;
1215}1180}
12161181
1217static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) {
1218 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
1219 const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8;
1220 const_instruction->base.value.special = ConstValSpecialStatic;
1221 bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value);
1222 return &const_instruction->base;
1223}
1224
1225static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1182static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1226 ZigType *type_entry)1183 ZigType *type_entry)
1227{1184{
...@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast...@@ -1429,7 +1386,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
14291386
1430static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,1387static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
1431 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1388 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1432 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,1389 bool is_comptime, FnInline fn_inline, bool is_async,
1433 IrInstruction *new_stack, ResultLoc *result_loc)1390 IrInstruction *new_stack, ResultLoc *result_loc)
1434{1391{
1435 IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);1392 IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);
...@@ -1440,22 +1397,24 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s...@@ -1440,22 +1397,24 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
1440 call_instruction->args = args;1397 call_instruction->args = args;
1441 call_instruction->arg_count = arg_count;1398 call_instruction->arg_count = arg_count;
1442 call_instruction->is_async = is_async;1399 call_instruction->is_async = is_async;
1443 call_instruction->async_allocator = async_allocator;
1444 call_instruction->new_stack = new_stack;1400 call_instruction->new_stack = new_stack;
1445 call_instruction->result_loc = result_loc;1401 call_instruction->result_loc = result_loc;
14461402
1447 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);1403 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
1448 for (size_t i = 0; i < arg_count; i += 1)1404 for (size_t i = 0; i < arg_count; i += 1)
1449 ir_ref_instruction(args[i], irb->current_basic_block);1405 ir_ref_instruction(args[i], irb->current_basic_block);
1450 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);1406 if (is_async && new_stack != nullptr) {
1407 // in this case the arg at the end is the return pointer
1408 ir_ref_instruction(args[arg_count], irb->current_basic_block);
1409 }
1451 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);1410 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
14521411
1453 return &call_instruction->base;1412 return &call_instruction->base;
1454}1413}
14551414
1456static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,1415static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
1457 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1416 ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1458 FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack,1417 FnInline fn_inline, bool is_async, IrInstruction *new_stack,
1459 IrInstruction *result_loc, ZigType *return_type)1418 IrInstruction *result_loc, ZigType *return_type)
1460{1419{
1461 IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,1420 IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,
...@@ -1467,18 +1426,16 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in...@@ -1467,18 +1426,16 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in
1467 call_instruction->args = args;1426 call_instruction->args = args;
1468 call_instruction->arg_count = arg_count;1427 call_instruction->arg_count = arg_count;
1469 call_instruction->is_async = is_async;1428 call_instruction->is_async = is_async;
1470 call_instruction->async_allocator = async_allocator;
1471 call_instruction->new_stack = new_stack;1429 call_instruction->new_stack = new_stack;
1472 call_instruction->result_loc = result_loc;1430 call_instruction->result_loc = result_loc;
14731431
1474 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);1432 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block);
1475 for (size_t i = 0; i < arg_count; i += 1)1433 for (size_t i = 0; i < arg_count; i += 1)
1476 ir_ref_instruction(args[i], ira->new_irb.current_basic_block);1434 ir_ref_instruction(args[i], ira->new_irb.current_basic_block);
1477 if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block);
1478 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);1435 if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block);
1479 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);1436 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
14801437
1481 return &call_instruction->base;1438 return call_instruction;
1482}1439}
14831440
1484static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,1441static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node,
...@@ -1754,17 +1711,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode...@@ -1754,17 +1711,16 @@ static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode
1754 return &instruction->base;1711 return &instruction->base;
1755}1712}
17561713
1757static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1714static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1758 IrInstruction *payload_type)1715 IrInstruction *payload_type)
1759{1716{
1760 IrInstructionPromiseType *instruction = ir_build_instruction<IrInstructionPromiseType>(irb, scope, source_node);1717 IrInstructionAnyFrameType *instruction = ir_build_instruction<IrInstructionAnyFrameType>(irb, scope, source_node);
1761 instruction->payload_type = payload_type;1718 instruction->payload_type = payload_type;
17621719
1763 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);1720 if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
17641721
1765 return &instruction->base;1722 return &instruction->base;
1766}1723}
1767
1768static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,1724static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1769 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)1725 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
1770{1726{
...@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo...@@ -2443,7 +2399,35 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo
2443}2399}
24442400
2445static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {2401static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2446 IrInstructionHandle *instruction = ir_build_instruction<IrInstructionHandle>(irb, scope, source_node);2402 IrInstructionFrameHandle *instruction = ir_build_instruction<IrInstructionFrameHandle>(irb, scope, source_node);
2403 return &instruction->base;
2404}
2405
2406static IrInstruction *ir_build_frame_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2407 IrInstructionFrameType *instruction = ir_build_instruction<IrInstructionFrameType>(irb, scope, source_node);
2408 instruction->fn = fn;
2409
2410 ir_ref_instruction(fn, irb->current_basic_block);
2411
2412 return &instruction->base;
2413}
2414
2415static IrInstruction *ir_build_frame_size_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
2416 IrInstructionFrameSizeSrc *instruction = ir_build_instruction<IrInstructionFrameSizeSrc>(irb, scope, source_node);
2417 instruction->fn = fn;
2418
2419 ir_ref_instruction(fn, irb->current_basic_block);
2420
2421 return &instruction->base;
2422}
2423
2424static IrInstruction *ir_build_frame_size_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn)
2425{
2426 IrInstructionFrameSizeGen *instruction = ir_build_instruction<IrInstructionFrameSizeGen>(irb, scope, source_node);
2427 instruction->fn = fn;
2428
2429 ir_ref_instruction(fn, irb->current_basic_block);
2430
2447 return &instruction->base;2431 return &instruction->base;
2448}2432}
24492433
...@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2546,11 +2530,12 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s
2546}2530}
25472531
2548static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,2532static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
2549 IrInstruction *base_ptr, bool resolve_err_set)2533 IrInstruction *base_ptr, bool resolve_err_set, bool base_ptr_is_payload)
2550{2534{
2551 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);2535 IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node);
2552 instruction->base_ptr = base_ptr;2536 instruction->base_ptr = base_ptr;
2553 instruction->resolve_err_set = resolve_err_set;2537 instruction->resolve_err_set = resolve_err_set;
2538 instruction->base_ptr_is_payload = base_ptr_is_payload;
25542539
2555 ir_ref_instruction(base_ptr, irb->current_basic_block);2540 ir_ref_instruction(base_ptr, irb->current_basic_block);
25562541
...@@ -2596,13 +2581,12 @@ static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope,...@@ -2596,13 +2581,12 @@ static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope,
25962581
2597static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,2582static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
2598 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,2583 IrInstruction **param_types, IrInstruction *align_value, IrInstruction *return_type,
2599 IrInstruction *async_allocator_type_value, bool is_var_args)2584 bool is_var_args)
2600{2585{
2601 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);2586 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
2602 instruction->param_types = param_types;2587 instruction->param_types = param_types;
2603 instruction->align_value = align_value;2588 instruction->align_value = align_value;
2604 instruction->return_type = return_type;2589 instruction->return_type = return_type;
2605 instruction->async_allocator_type_value = async_allocator_type_value;
2606 instruction->is_var_args = is_var_args;2590 instruction->is_var_args = is_var_args;
26072591
2608 assert(source_node->type == NodeTypeFnProto);2592 assert(source_node->type == NodeTypeFnProto);
...@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2612,7 +2596,6 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
2612 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);2596 if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
2613 }2597 }
2614 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);2598 if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
2615 if (async_allocator_type_value != nullptr) ir_ref_instruction(async_allocator_type_value, irb->current_basic_block);
2616 ir_ref_instruction(return_type, irb->current_basic_block);2599 ir_ref_instruction(return_type, irb->current_basic_block);
26172600
2618 return &instruction->base;2601 return &instruction->base;
...@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod...@@ -2994,18 +2977,6 @@ static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNod
2994 return &instruction->base;2977 return &instruction->base;
2995}2978}
29962979
2997static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
2998 ResultLoc *result_loc, IrInstruction *result)
2999{
3000 IrInstructionResultPtr *instruction = ir_build_instruction<IrInstructionResultPtr>(irb, scope, source_node);
3001 instruction->result_loc = result_loc;
3002 instruction->result = result;
3003
3004 ir_ref_instruction(result, irb->current_basic_block);
3005
3006 return &instruction->base;
3007}
3008
3009static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {2980static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3010 IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);2981 IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
30112982
...@@ -3056,149 +3027,6 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode...@@ -3056,149 +3027,6 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
3056 return &instruction->base;3027 return &instruction->base;
3057}3028}
30583029
3059static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node,
3060 IrInstruction *target)
3061{
3062 IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
3063 instruction->target = target;
3064
3065 ir_ref_instruction(target, irb->current_basic_block);
3066
3067 return &instruction->base;
3068}
3069
3070static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node,
3071 ImplicitAllocatorId id)
3072{
3073 IrInstructionGetImplicitAllocator *instruction = ir_build_instruction<IrInstructionGetImplicitAllocator>(irb, scope, source_node);
3074 instruction->id = id;
3075
3076 return &instruction->base;
3077}
3078
3079static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) {
3080 IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);
3081 instruction->promise_ptr = promise_ptr;
3082
3083 ir_ref_instruction(promise_ptr, irb->current_basic_block);
3084
3085 return &instruction->base;
3086}
3087
3088static IrInstruction *ir_build_coro_alloc(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id) {
3089 IrInstructionCoroAlloc *instruction = ir_build_instruction<IrInstructionCoroAlloc>(irb, scope, source_node);
3090 instruction->coro_id = coro_id;
3091
3092 ir_ref_instruction(coro_id, irb->current_basic_block);
3093
3094 return &instruction->base;
3095}
3096
3097static IrInstruction *ir_build_coro_size(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3098 IrInstructionCoroSize *instruction = ir_build_instruction<IrInstructionCoroSize>(irb, scope, source_node);
3099
3100 return &instruction->base;
3101}
3102
3103static IrInstruction *ir_build_coro_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id, IrInstruction *coro_mem_ptr) {
3104 IrInstructionCoroBegin *instruction = ir_build_instruction<IrInstructionCoroBegin>(irb, scope, source_node);
3105 instruction->coro_id = coro_id;
3106 instruction->coro_mem_ptr = coro_mem_ptr;
3107
3108 ir_ref_instruction(coro_id, irb->current_basic_block);
3109 ir_ref_instruction(coro_mem_ptr, irb->current_basic_block);
3110
3111 return &instruction->base;
3112}
3113
3114static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_val) {
3115 IrInstructionCoroAllocFail *instruction = ir_build_instruction<IrInstructionCoroAllocFail>(irb, scope, source_node);
3116 instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
3117 instruction->base.value.special = ConstValSpecialStatic;
3118 instruction->err_val = err_val;
3119
3120 ir_ref_instruction(err_val, irb->current_basic_block);
3121
3122 return &instruction->base;
3123}
3124
3125static IrInstruction *ir_build_coro_suspend(IrBuilder *irb, Scope *scope, AstNode *source_node,
3126 IrInstruction *save_point, IrInstruction *is_final)
3127{
3128 IrInstructionCoroSuspend *instruction = ir_build_instruction<IrInstructionCoroSuspend>(irb, scope, source_node);
3129 instruction->save_point = save_point;
3130 instruction->is_final = is_final;
3131
3132 if (save_point != nullptr) ir_ref_instruction(save_point, irb->current_basic_block);
3133 ir_ref_instruction(is_final, irb->current_basic_block);
3134
3135 return &instruction->base;
3136}
3137
3138static IrInstruction *ir_build_coro_end(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3139 IrInstructionCoroEnd *instruction = ir_build_instruction<IrInstructionCoroEnd>(irb, scope, source_node);
3140 return &instruction->base;
3141}
3142
3143static IrInstruction *ir_build_coro_free(IrBuilder *irb, Scope *scope, AstNode *source_node,
3144 IrInstruction *coro_id, IrInstruction *coro_handle)
3145{
3146 IrInstructionCoroFree *instruction = ir_build_instruction<IrInstructionCoroFree>(irb, scope, source_node);
3147 instruction->coro_id = coro_id;
3148 instruction->coro_handle = coro_handle;
3149
3150 ir_ref_instruction(coro_id, irb->current_basic_block);
3151 ir_ref_instruction(coro_handle, irb->current_basic_block);
3152
3153 return &instruction->base;
3154}
3155
3156static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,
3157 IrInstruction *awaiter_handle)
3158{
3159 IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node);
3160 instruction->awaiter_handle = awaiter_handle;
3161
3162 ir_ref_instruction(awaiter_handle, irb->current_basic_block);
3163
3164 return &instruction->base;
3165}
3166
3167static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *source_node,
3168 IrInstruction *coro_handle)
3169{
3170 IrInstructionCoroSave *instruction = ir_build_instruction<IrInstructionCoroSave>(irb, scope, source_node);
3171 instruction->coro_handle = coro_handle;
3172
3173 ir_ref_instruction(coro_handle, irb->current_basic_block);
3174
3175 return &instruction->base;
3176}
3177
3178static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node,
3179 IrInstruction *coro_handle)
3180{
3181 IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node);
3182 instruction->coro_handle = coro_handle;
3183
3184 ir_ref_instruction(coro_handle, irb->current_basic_block);
3185
3186 return &instruction->base;
3187}
3188
3189static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
3190 IrInstruction *realloc_fn, IrInstruction *coro_size)
3191{
3192 IrInstructionCoroAllocHelper *instruction = ir_build_instruction<IrInstructionCoroAllocHelper>(irb, scope, source_node);
3193 instruction->realloc_fn = realloc_fn;
3194 instruction->coro_size = coro_size;
3195
3196 ir_ref_instruction(realloc_fn, irb->current_basic_block);
3197 ir_ref_instruction(coro_size, irb->current_basic_block);
3198
3199 return &instruction->base;
3200}
3201
3202static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,3030static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
3203 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,3031 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
3204 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)3032 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
...@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode...@@ -3238,28 +3066,6 @@ static IrInstruction *ir_build_atomic_load(IrBuilder *irb, Scope *scope, AstNode
3238 return &instruction->base;3066 return &instruction->base;
3239}3067}
32403068
3241static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
3242 IrInstruction *promise_type)
3243{
3244 IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node);
3245 instruction->promise_type = promise_type;
3246
3247 ir_ref_instruction(promise_type, irb->current_basic_block);
3248
3249 return &instruction->base;
3250}
3251
3252static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, AstNode *source_node,
3253 IrInstruction *promise_result_type)
3254{
3255 IrInstructionAwaitBookkeeping *instruction = ir_build_instruction<IrInstructionAwaitBookkeeping>(irb, scope, source_node);
3256 instruction->promise_result_type = promise_result_type;
3257
3258 ir_ref_instruction(promise_result_type, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
3263static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {3069static IrInstruction *ir_build_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3264 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);3070 IrInstructionSaveErrRetAddr *instruction = ir_build_instruction<IrInstructionSaveErrRetAddr>(irb, scope, source_node);
3265 return &instruction->base;3071 return &instruction->base;
...@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s...@@ -3276,30 +3082,6 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
3276 return &instruction->base;3082 return &instruction->base;
3277}3083}
32783084
3279static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
3280 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
3281{
3282 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
3283 instruction->coro_promise_ptr = coro_promise_ptr;
3284 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
3285 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
3286
3287 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
3288 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
3289 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
3290
3291 return &instruction->base;
3292}
3293
3294static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
3295 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
3296 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
3297
3298 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
3299
3300 return &instruction->base;
3301}
3302
3303static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,3085static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
3304 IrInstruction *container, IrInstruction *name)3086 IrInstruction *container, IrInstruction *name)
3305{3087{
...@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode...@@ -3435,7 +3217,7 @@ static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode
3435 return &instruction->base;3217 return &instruction->base;
3436}3218}
34373219
3438static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,3220static IrInstructionAllocaGen *ir_build_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3439 uint32_t align, const char *name_hint)3221 uint32_t align, const char *name_hint)
3440{3222{
3441 IrInstructionAllocaGen *instruction = ir_create_instruction<IrInstructionAllocaGen>(&ira->new_irb,3223 IrInstructionAllocaGen *instruction = ir_create_instruction<IrInstructionAllocaGen>(&ira->new_irb,
...@@ -3459,6 +3241,87 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s...@@ -3459,6 +3241,87 @@ static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *s
3459 return &instruction->base;3241 return &instruction->base;
3460}3242}
34613243
3244static IrInstructionSuspendBegin *ir_build_suspend_begin(IrBuilder *irb, Scope *scope, AstNode *source_node) {
3245 IrInstructionSuspendBegin *instruction = ir_build_instruction<IrInstructionSuspendBegin>(irb, scope, source_node);
3246 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3247
3248 return instruction;
3249}
3250
3251static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstNode *source_node,
3252 IrInstructionSuspendBegin *begin)
3253{
3254 IrInstructionSuspendFinish *instruction = ir_build_instruction<IrInstructionSuspendFinish>(irb, scope, source_node);
3255 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3256 instruction->begin = begin;
3257
3258 ir_ref_instruction(&begin->base, irb->current_basic_block);
3259
3260 return &instruction->base;
3261}
3262
3263static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
3264 IrInstruction *frame, ResultLoc *result_loc)
3265{
3266 IrInstructionAwaitSrc *instruction = ir_build_instruction<IrInstructionAwaitSrc>(irb, scope, source_node);
3267 instruction->frame = frame;
3268 instruction->result_loc = result_loc;
3269
3270 ir_ref_instruction(frame, irb->current_basic_block);
3271
3272 return &instruction->base;
3273}
3274
3275static IrInstruction *ir_build_await_gen(IrAnalyze *ira, IrInstruction *source_instruction,
3276 IrInstruction *frame, ZigType *result_type, IrInstruction *result_loc)
3277{
3278 IrInstructionAwaitGen *instruction = ir_build_instruction<IrInstructionAwaitGen>(&ira->new_irb,
3279 source_instruction->scope, source_instruction->source_node);
3280 instruction->base.value.type = result_type;
3281 instruction->frame = frame;
3282 instruction->result_loc = result_loc;
3283
3284 ir_ref_instruction(frame, ira->new_irb.current_basic_block);
3285 if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
3286
3287 return &instruction->base;
3288}
3289
3290static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {
3291 IrInstructionResume *instruction = ir_build_instruction<IrInstructionResume>(irb, scope, source_node);
3292 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3293 instruction->frame = frame;
3294
3295 ir_ref_instruction(frame, irb->current_basic_block);
3296
3297 return &instruction->base;
3298}
3299
3300static IrInstructionSpillBegin *ir_build_spill_begin(IrBuilder *irb, Scope *scope, AstNode *source_node,
3301 IrInstruction *operand, SpillId spill_id)
3302{
3303 IrInstructionSpillBegin *instruction = ir_build_instruction<IrInstructionSpillBegin>(irb, scope, source_node);
3304 instruction->base.value.special = ConstValSpecialStatic;
3305 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3306 instruction->operand = operand;
3307 instruction->spill_id = spill_id;
3308
3309 ir_ref_instruction(operand, irb->current_basic_block);
3310
3311 return instruction;
3312}
3313
3314static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode *source_node,
3315 IrInstructionSpillBegin *begin)
3316{
3317 IrInstructionSpillEnd *instruction = ir_build_instruction<IrInstructionSpillEnd>(irb, scope, source_node);
3318 instruction->begin = begin;
3319
3320 ir_ref_instruction(&begin->base, irb->current_basic_block);
3321
3322 return &instruction->base;
3323}
3324
3462static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {3325static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
3463 results[ReturnKindUnconditional] = 0;3326 results[ReturnKindUnconditional] = 0;
3464 results[ReturnKindError] = 0;3327 results[ReturnKindError] = 0;
...@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco...@@ -3489,7 +3352,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
3489 continue;3352 continue;
3490 case ScopeIdDeferExpr:3353 case ScopeIdDeferExpr:
3491 case ScopeIdCImport:3354 case ScopeIdCImport:
3492 case ScopeIdCoroPrelude:
3493 zig_unreachable();3355 zig_unreachable();
3494 }3356 }
3495 }3357 }
...@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -3545,7 +3407,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
3545 continue;3407 continue;
3546 case ScopeIdDeferExpr:3408 case ScopeIdDeferExpr:
3547 case ScopeIdCImport:3409 case ScopeIdCImport:
3548 case ScopeIdCoroPrelude:
3549 zig_unreachable();3410 zig_unreachable();
3550 }3411 }
3551 }3412 }
...@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -3588,66 +3449,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
3588 return nullptr;3449 return nullptr;
3589}3450}
35903451
3591static bool exec_is_async(IrExecutable *exec) {
3592 ZigFn *fn_entry = exec_fn_entry(exec);
3593 return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
3594}
3595
3596static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
3597 bool is_generated_code)
3598{
3599 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3600
3601 bool is_async = exec_is_async(irb->exec);
3602 if (!is_async) {
3603 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
3604 return_inst->is_gen = is_generated_code;
3605 return return_inst;
3606 }
3607
3608 IrBasicBlock *suspended_block = ir_create_basic_block(irb, scope, "Suspended");
3609 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, scope, "NotSuspended");
3610 IrBasicBlock *store_awaiter_block = ir_create_basic_block(irb, scope, "StoreAwaiter");
3611 IrBasicBlock *check_canceled_block = ir_create_basic_block(irb, scope, "CheckCanceled");
3612
3613 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
3614 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
3615 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
3616 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
3617 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
3618 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
3619 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
3620
3621 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
3622 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
3623 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
3624 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, ptr_mask, nullptr,
3625 AtomicRmwOp_or, AtomicOrderSeqCst);
3626
3627 IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
3628 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
3629 ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
3630
3631 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
3632 ir_build_unreachable(irb, scope, node);
3633
3634 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
3635 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
3636 // if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
3637 IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
3638 ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
3639
3640 ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
3641 IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
3642 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, await_handle);
3643 ir_build_br(irb, scope, node, irb->exec->coro_normal_final, is_comptime);
3644
3645 ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
3646 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
3647 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
3648 return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
3649}
3650
3651static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {3452static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) {
3652 assert(node->type == NodeTypeReturnExpr);3453 assert(node->type == NodeTypeReturnExpr);
36533454
...@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3689,57 +3490,58 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3689 return_value = ir_build_const_void(irb, scope, node);3490 return_value = ir_build_const_void(irb, scope, node);
3690 }3491 }
36913492
3493 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
3494
3692 size_t defer_counts[2];3495 size_t defer_counts[2];
3693 ir_count_defers(irb, scope, outer_scope, defer_counts);3496 ir_count_defers(irb, scope, outer_scope, defer_counts);
3694 bool have_err_defers = defer_counts[ReturnKindError] > 0;3497 bool have_err_defers = defer_counts[ReturnKindError] > 0;
3695 if (have_err_defers || irb->codegen->have_err_ret_tracing) {3498 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
3696 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");3499 // only generate unconditional defers
3697 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");3500 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3698 if (!have_err_defers) {3501 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3699 ir_gen_defers_for_block(irb, scope, outer_scope, false);3502 result_loc_ret->base.source_instruction = result;
3700 }3503 return result;
3504 }
3505 bool should_inline = ir_should_inline(irb->exec, scope);
37013506
3702 IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base,3507 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
3703 return_value);3508 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
3704 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false);
37053509
3706 bool should_inline = ir_should_inline(irb->exec, scope);3510 if (!have_err_defers) {
3707 IrInstruction *is_comptime;3511 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3708 if (should_inline) {3512 }
3709 is_comptime = ir_build_const_bool(irb, scope, node, true);
3710 } else {
3711 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3712 }
37133513
3714 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));3514 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
3715 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
37163515
3717 ir_set_cursor_at_end_and_append_block(irb, err_block);3516 IrInstruction *is_comptime;
3718 if (have_err_defers) {3517 if (should_inline) {
3719 ir_gen_defers_for_block(irb, scope, outer_scope, true);3518 is_comptime = ir_build_const_bool(irb, scope, node, should_inline);
3720 }3519 } else {
3721 if (irb->codegen->have_err_ret_tracing && !should_inline) {3520 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
3722 ir_build_save_err_ret_addr(irb, scope, node);3521 }
3723 }
3724 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
37253522
3726 ir_set_cursor_at_end_and_append_block(irb, ok_block);3523 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
3727 if (have_err_defers) {3524 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
3728 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3729 }
3730 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
37313525
3732 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);3526 ir_set_cursor_at_end_and_append_block(irb, err_block);
3733 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);3527 if (have_err_defers) {
3734 result_loc_ret->base.source_instruction = result;3528 ir_gen_defers_for_block(irb, scope, outer_scope, true);
3735 return result;3529 }
3736 } else {3530 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3737 // generate unconditional defers3531 ir_build_save_err_ret_addr(irb, scope, node);
3532 }
3533 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3534
3535 ir_set_cursor_at_end_and_append_block(irb, ok_block);
3536 if (have_err_defers) {
3738 ir_gen_defers_for_block(irb, scope, outer_scope, false);3537 ir_gen_defers_for_block(irb, scope, outer_scope, false);
3739 IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false);
3740 result_loc_ret->base.source_instruction = result;
3741 return result;
3742 }3538 }
3539 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
3540
3541 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
3542 IrInstruction *result = ir_build_return(irb, scope, node, return_value);
3543 result_loc_ret->base.source_instruction = result;
3544 return result;
3743 }3545 }
3744 case ReturnKindError:3546 case ReturnKindError:
3745 {3547 {
...@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3747,7 +3549,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3747 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);3549 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
3748 if (err_union_ptr == irb->codegen->invalid_instruction)3550 if (err_union_ptr == irb->codegen->invalid_instruction)
3749 return irb->codegen->invalid_instruction;3551 return irb->codegen->invalid_instruction;
3750 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true);3552 IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true, false);
37513553
3752 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");3554 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
3753 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");3555 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
...@@ -3761,19 +3563,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3761,19 +3563,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3761 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));3563 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
37623564
3763 ir_set_cursor_at_end_and_append_block(irb, return_block);3565 ir_set_cursor_at_end_and_append_block(irb, return_block);
3566 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3567 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3568 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val));
3569 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3570 SpillIdRetErrCode);
3571 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3572 result_loc_ret->base.id = ResultLocIdReturn;
3573 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3574 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
3764 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {3575 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
3765 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
3766 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
3767
3768 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3769 result_loc_ret->base.id = ResultLocIdReturn;
3770 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3771 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
3772
3773 if (irb->codegen->have_err_ret_tracing && !should_inline) {3576 if (irb->codegen->have_err_ret_tracing && !should_inline) {
3774 ir_build_save_err_ret_addr(irb, scope, node);3577 ir_build_save_err_ret_addr(irb, scope, node);
3775 }3578 }
3776 IrInstruction *ret_inst = ir_gen_async_return(irb, scope, node, err_val, false);3579 err_val = ir_build_spill_end(irb, scope, node, spill_begin);
3580 IrInstruction *ret_inst = ir_build_return(irb, scope, node, err_val);
3777 result_loc_ret->base.source_instruction = ret_inst;3581 result_loc_ret->base.source_instruction = ret_inst;
3778 }3582 }
37793583
...@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3971,18 +3775,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3971 incoming_values.append(else_expr_result);3775 incoming_values.append(else_expr_result);
3972 }3776 }
39733777
3974 if (block_node->data.block.name != nullptr) {3778 bool is_return_from_fn = block_node == irb->main_block_node;
3779 if (!is_return_from_fn) {
3975 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);3780 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3781 }
3782
3783 IrInstruction *result;
3784 if (block_node->data.block.name != nullptr) {
3976 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));3785 ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
3977 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);3786 ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block);
3978 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,3787 IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length,
3979 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);3788 incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
3980 return ir_expr_wrap(irb, parent_scope, phi, result_loc);3789 result = ir_expr_wrap(irb, parent_scope, phi, result_loc);
3981 } else {3790 } else {
3982 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3983 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));3791 IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3984 return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);3792 result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc);
3985 }3793 }
3794 if (!is_return_from_fn)
3795 return result;
3796
3797 // no need for save_err_ret_addr because this cannot return error
3798 // only generate unconditional defers
3799
3800 ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result));
3801 ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3802 return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result));
3986}3803}
39873804
3988static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {3805static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
...@@ -4561,8 +4378,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4561,8 +4378,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4561 return irb->codegen->invalid_instruction;4378 return irb->codegen->invalid_instruction;
4562 }4379 }
45634380
4564 bool is_async = exec_is_async(irb->exec);
4565
4566 switch (builtin_fn->id) {4381 switch (builtin_fn->id) {
4567 case BuiltinFnIdInvalid:4382 case BuiltinFnIdInvalid:
4568 zig_unreachable();4383 zig_unreachable();
...@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5185,16 +5000,30 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5185 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);5000 return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);
5186 case BuiltinFnIdFrameAddress:5001 case BuiltinFnIdFrameAddress:
5187 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);5002 return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);
5188 case BuiltinFnIdHandle:5003 case BuiltinFnIdFrameHandle:
5189 if (!irb->exec->fn_entry) {5004 if (!irb->exec->fn_entry) {
5190 add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));5005 add_node_error(irb->codegen, node, buf_sprintf("@frame() called outside of function definition"));
5191 return irb->codegen->invalid_instruction;
5192 }
5193 if (!is_async) {
5194 add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
5195 return irb->codegen->invalid_instruction;5006 return irb->codegen->invalid_instruction;
5196 }5007 }
5197 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);5008 return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);
5009 case BuiltinFnIdFrameType: {
5010 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5011 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5012 if (arg0_value == irb->codegen->invalid_instruction)
5013 return arg0_value;
5014
5015 IrInstruction *frame_type = ir_build_frame_type(irb, scope, node, arg0_value);
5016 return ir_lval_wrap(irb, scope, frame_type, lval, result_loc);
5017 }
5018 case BuiltinFnIdFrameSize: {
5019 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5020 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5021 if (arg0_value == irb->codegen->invalid_instruction)
5022 return arg0_value;
5023
5024 IrInstruction *frame_size = ir_build_frame_size_src(irb, scope, node, arg0_value);
5025 return ir_lval_wrap(irb, scope, frame_size, lval, result_loc);
5026 }
5198 case BuiltinFnIdAlignOf:5027 case BuiltinFnIdAlignOf:
5199 {5028 {
5200 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);5029 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -5395,13 +5224,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5395,13 +5224,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5395 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;5224 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
53965225
5397 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,5226 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5398 fn_inline, false, nullptr, nullptr, result_loc);5227 fn_inline, false, nullptr, result_loc);
5399 return ir_lval_wrap(irb, scope, call, lval, result_loc);5228 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5400 }5229 }
5401 case BuiltinFnIdNewStackCall:5230 case BuiltinFnIdNewStackCall:
5402 {5231 {
5403 if (node->data.fn_call_expr.params.length == 0) {5232 if (node->data.fn_call_expr.params.length < 2) {
5404 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));5233 add_node_error(irb->codegen, node,
5234 buf_sprintf("expected at least 2 arguments, found %" ZIG_PRI_usize,
5235 node->data.fn_call_expr.params.length));
5405 return irb->codegen->invalid_instruction;5236 return irb->codegen->invalid_instruction;
5406 }5237 }
54075238
...@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5426,7 +5257,51 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5426 }5257 }
54275258
5428 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,5259 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5429 FnInlineAuto, false, nullptr, new_stack, result_loc);5260 FnInlineAuto, false, new_stack, result_loc);
5261 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5262 }
5263 case BuiltinFnIdAsyncCall:
5264 {
5265 size_t arg_offset = 3;
5266 if (node->data.fn_call_expr.params.length < arg_offset) {
5267 add_node_error(irb->codegen, node,
5268 buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
5269 arg_offset, node->data.fn_call_expr.params.length));
5270 return irb->codegen->invalid_instruction;
5271 }
5272
5273 AstNode *bytes_node = node->data.fn_call_expr.params.at(0);
5274 IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
5275 if (bytes == irb->codegen->invalid_instruction)
5276 return bytes;
5277
5278 AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1);
5279 IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
5280 if (ret_ptr == irb->codegen->invalid_instruction)
5281 return ret_ptr;
5282
5283 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2);
5284 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
5285 if (fn_ref == irb->codegen->invalid_instruction)
5286 return fn_ref;
5287
5288 size_t arg_count = node->data.fn_call_expr.params.length - arg_offset;
5289
5290 // last "arg" is return pointer
5291 IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
5292
5293 for (size_t i = 0; i < arg_count; i += 1) {
5294 AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset);
5295 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
5296 if (arg == irb->codegen->invalid_instruction)
5297 return arg;
5298 args[i] = arg;
5299 }
5300
5301 args[arg_count] = ret_ptr;
5302
5303 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5304 FnInlineAuto, true, bytes, result_loc);
5430 return ir_lval_wrap(irb, scope, call, lval, result_loc);5305 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5431 }5306 }
5432 case BuiltinFnIdTypeId:5307 case BuiltinFnIdTypeId:
...@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node...@@ -5731,17 +5606,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
5731 }5606 }
57325607
5733 bool is_async = node->data.fn_call_expr.is_async;5608 bool is_async = node->data.fn_call_expr.is_async;
5734 IrInstruction *async_allocator = nullptr;5609 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5735 if (is_async) {5610 FnInlineAuto, is_async, nullptr, result_loc);
5736 if (node->data.fn_call_expr.async_allocator) {
5737 async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
5738 if (async_allocator == irb->codegen->invalid_instruction)
5739 return async_allocator;
5740 }
5741 }
5742
5743 IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
5744 is_async, async_allocator, nullptr, result_loc);
5745 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);5611 return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);
5746}5612}
57475613
...@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -6254,7 +6120,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
6254 LValPtr, nullptr);6120 LValPtr, nullptr);
6255 if (err_val_ptr == irb->codegen->invalid_instruction)6121 if (err_val_ptr == irb->codegen->invalid_instruction)
6256 return err_val_ptr;6122 return err_val_ptr;
6257 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, true);6123 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr,
6124 true, false);
6258 IrBasicBlock *after_cond_block = irb->current_basic_block;6125 IrBasicBlock *after_cond_block = irb->current_basic_block;
6259 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));6126 IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
6260 IrInstruction *cond_br_inst;6127 IrInstruction *cond_br_inst;
...@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n...@@ -6762,10 +6629,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
6762 }6629 }
6763}6630}
67646631
6765static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode *node) {6632static IrInstruction *ir_gen_anyframe_type(IrBuilder *irb, Scope *scope, AstNode *node) {
6766 assert(node->type == NodeTypePromiseType);6633 assert(node->type == NodeTypeAnyFrameType);
67676634
6768 AstNode *payload_type_node = node->data.promise_type.payload_type;6635 AstNode *payload_type_node = node->data.anyframe_type.payload_type;
6769 IrInstruction *payload_type_value = nullptr;6636 IrInstruction *payload_type_value = nullptr;
67706637
6771 if (payload_type_node != nullptr) {6638 if (payload_type_node != nullptr) {
...@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode...@@ -6775,7 +6642,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
67756642
6776 }6643 }
67776644
6778 return ir_build_promise_type(irb, scope, node, payload_type_value);6645 return ir_build_anyframe_type(irb, scope, node, payload_type_value);
6779}6646}
67806647
6781static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {6648static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -7070,7 +6937,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -7070,7 +6937,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
7070 return err_val_ptr;6937 return err_val_ptr;
70716938
7072 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);6939 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
7073 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true);6940 IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true, false);
70746941
7075 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");6942 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
7076 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");6943 IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
...@@ -7686,7 +7553,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -7686,7 +7553,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
7686 if (err_union_ptr == irb->codegen->invalid_instruction)7553 if (err_union_ptr == irb->codegen->invalid_instruction)
7687 return irb->codegen->invalid_instruction;7554 return irb->codegen->invalid_instruction;
76887555
7689 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true);7556 IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true, false);
76907557
7691 IrInstruction *is_comptime;7558 IrInstruction *is_comptime;
7692 if (ir_should_inline(irb->exec, parent_scope)) {7559 if (ir_should_inline(irb->exec, parent_scope)) {
...@@ -7980,339 +7847,45 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -7980,339 +7847,45 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
7980 //return_type = nullptr;7847 //return_type = nullptr;
7981 }7848 }
79827849
7983 IrInstruction *async_allocator_type_value = nullptr;7850 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
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);
8124}7851}
81257852
8126static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {7853static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
8127 assert(node->type == NodeTypeResume);7854 assert(node->type == NodeTypeResume);
81287855
8129 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);7856 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr);
8130 if (target_inst == irb->codegen->invalid_instruction)7857 if (target_inst == irb->codegen->invalid_instruction)
8131 return irb->codegen->invalid_instruction;7858 return irb->codegen->invalid_instruction;
81327859
8133 return ir_gen_resume_target(irb, scope, node, target_inst);7860 return ir_build_resume(irb, scope, node, target_inst);
8134}7861}
81357862
8136static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {7863static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
7864 ResultLoc *result_loc)
7865{
8137 assert(node->type == NodeTypeAwaitExpr);7866 assert(node->type == NodeTypeAwaitExpr);
81387867
8139 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
8140 if (target_inst == irb->codegen->invalid_instruction)
8141 return irb->codegen->invalid_instruction;
8142
8143 ZigFn *fn_entry = exec_fn_entry(irb->exec);7868 ZigFn *fn_entry = exec_fn_entry(irb->exec);
8144 if (!fn_entry) {7869 if (!fn_entry) {
8145 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));7870 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
8146 return irb->codegen->invalid_instruction;7871 return irb->codegen->invalid_instruction;
8147 }7872 }
8148 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {7873 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
8149 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));7874 if (existing_suspend_scope) {
8150 return irb->codegen->invalid_instruction;7875 if (!existing_suspend_scope->reported_err) {
8151 }7876 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block"));
81527877 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
8153 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);7878 existing_suspend_scope->reported_err = true;
8154 if (scope_defer_expr) {
8155 if (!scope_defer_expr->reported_err) {
8156 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
8157 scope_defer_expr->reported_err = true;
8158 }7879 }
8159 return irb->codegen->invalid_instruction;7880 return irb->codegen->invalid_instruction;
8160 }7881 }
81617882
8162 Scope *outer_scope = irb->exec->begin_scope;7883 IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr);
7884 if (target_inst == irb->codegen->invalid_instruction)
7885 return irb->codegen->invalid_instruction;
81637886
8164 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);7887 IrInstruction *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc);
8165 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);7888 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
8166 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8167
8168 if (irb->codegen->have_err_ret_tracing) {
8169 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8170 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8171 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8172 ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
8173 }
8174
8175 IrBasicBlock *already_awaited_block = ir_create_basic_block(irb, scope, "AlreadyAwaited");
8176 IrBasicBlock *not_awaited_block = ir_create_basic_block(irb, scope, "NotAwaited");
8177 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled");
8178 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, scope, "YesSuspend");
8179 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, scope, "NoSuspend");
8180 IrBasicBlock *merge_block = ir_create_basic_block(irb, scope, "MergeSuspend");
8181 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, scope, "SuspendCleanup");
8182 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "SuspendResume");
8183 IrBasicBlock *cancel_target_block = ir_create_basic_block(irb, scope, "CancelTarget");
8184 IrBasicBlock *do_cancel_block = ir_create_basic_block(irb, scope, "DoCancel");
8185 IrBasicBlock *do_defers_block = ir_create_basic_block(irb, scope, "DoDefers");
8186 IrBasicBlock *destroy_block = ir_create_basic_block(irb, scope, "DestroyBlock");
8187 IrBasicBlock *my_suspended_block = ir_create_basic_block(irb, scope, "AlreadySuspended");
8188 IrBasicBlock *my_not_suspended_block = ir_create_basic_block(irb, scope, "NotAlreadySuspended");
8189 IrBasicBlock *do_suspend_block = ir_create_basic_block(irb, scope, "DoSuspend");
8190
8191 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8192 IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8193 atomic_state_field_name, false);
8194
8195 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
8196 IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
8197 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
8198 IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
8199 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8200 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
8201 IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8202 IrInstruction *await_mask = ir_build_const_usize(irb, scope, node, 0x4); // 0b100
8203 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001
8204 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
8205
8206 ZigVar *result_var = ir_create_var(irb, node, scope, nullptr,
8207 false, false, true, const_bool_false);
8208 IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
8209 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
8210 ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
8211 IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef, nullptr);
8212 build_decl_var_and_init(irb, scope, node, result_var, undef_promise_result, "result", const_bool_false);
8213 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
8214 ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
8215 IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
8216
8217 IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
8218 IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false);
8219 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8220 usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr,
8221 AtomicRmwOp_or, AtomicOrderSeqCst);
8222
8223 IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
8224 IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
8225 ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
8226
8227 ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
8228 ir_build_unreachable(irb, scope, node);
8229
8230 ir_set_cursor_at_end_and_append_block(irb, not_awaited_block);
8231 IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8232 IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8233 IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8234 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8235 ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
8236
8237 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8238 ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
8239
8240 ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
8241 ir_build_cancel(irb, scope, node, target_inst);
8242 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8243
8244 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
8245 if (irb->codegen->have_err_ret_tracing) {
8246 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8247 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8248 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
8249 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
8250 }
8251 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8252 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8253 // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
8254 // because we're about to destroy the memory. So we store it into our result variable.
8255 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
8256 ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
8257 ir_build_cancel(irb, scope, node, target_inst);
8258 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8259
8260
8261 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
8262 IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8263 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8264 AtomicRmwOp_or, AtomicOrderSeqCst);
8265 IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
8266 IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
8267 ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
8268
8269 ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
8270 ir_build_unreachable(irb, scope, node);
8271
8272 ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
8273 IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
8274 IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
8275 ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
8276
8277 ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
8278 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
8279
8280 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8281 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8282 cases[0].block = resume_block;
8283 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8284 cases[1].block = destroy_block;
8285 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
8286 2, cases, const_bool_false, nullptr);
8287
8288 ir_set_cursor_at_end_and_append_block(irb, destroy_block);
8289 ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
8290 ir_mark_gen(ir_build_br(irb, scope, node, cleanup_block, const_bool_false));
8291
8292 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8293 IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false);
8294 IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
8295 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr,
8296 AtomicRmwOp_or, AtomicOrderSeqCst);
8297 IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
8298 IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
8299 IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
8300 ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
8301
8302 ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
8303 IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
8304 ir_gen_cancel_target(irb, scope, node, my_await_handle, true, false);
8305 ir_mark_gen(ir_build_br(irb, scope, node, do_defers_block, const_bool_false));
8306
8307 ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
8308 ir_gen_defers_for_block(irb, scope, outer_scope, true);
8309 ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
8310
8311 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8312 ir_build_br(irb, scope, node, merge_block, const_bool_false);
8313
8314 ir_set_cursor_at_end_and_append_block(irb, merge_block);
8315 return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
8316}7889}
83177890
8318static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {7891static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
...@@ -8323,20 +7896,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -8323,20 +7896,6 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
8323 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));7896 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
8324 return irb->codegen->invalid_instruction;7897 return irb->codegen->invalid_instruction;
8325 }7898 }
8326 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
8327 add_node_error(irb->codegen, node, buf_sprintf("suspend in non-async function"));
8328 return irb->codegen->invalid_instruction;
8329 }
8330
8331 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
8332 if (scope_defer_expr) {
8333 if (!scope_defer_expr->reported_err) {
8334 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
8335 add_error_note(irb->codegen, msg, scope_defer_expr->base.source_node, buf_sprintf("defer here"));
8336 scope_defer_expr->reported_err = true;
8337 }
8338 return irb->codegen->invalid_instruction;
8339 }
8340 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);7899 ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
8341 if (existing_suspend_scope) {7900 if (existing_suspend_scope) {
8342 if (!existing_suspend_scope->reported_err) {7901 if (!existing_suspend_scope->reported_err) {
...@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -8347,91 +7906,15 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
8347 return irb->codegen->invalid_instruction;7906 return irb->codegen->invalid_instruction;
8348 }7907 }
83497908
8350 Scope *outer_scope = irb->exec->begin_scope;7909 IrInstructionSuspendBegin *begin = ir_build_suspend_begin(irb, parent_scope, node);
83517910 if (node->data.suspend.block != nullptr) {
8352 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
8353 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
8354 IrBasicBlock *suspended_block = ir_create_basic_block(irb, parent_scope, "AlreadySuspended");
8355 IrBasicBlock *canceled_block = ir_create_basic_block(irb, parent_scope, "IsCanceled");
8356 IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, parent_scope, "NotCanceled");
8357 IrBasicBlock *not_suspended_block = ir_create_basic_block(irb, parent_scope, "NotAlreadySuspended");
8358 IrBasicBlock *cancel_awaiter_block = ir_create_basic_block(irb, parent_scope, "CancelAwaiter");
8359
8360 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_promise);
8361 IrInstruction *const_bool_true = ir_build_const_bool(irb, parent_scope, node, true);
8362 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
8363 IrInstruction *usize_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_usize);
8364 IrInstruction *is_canceled_mask = ir_build_const_usize(irb, parent_scope, node, 0x1); // 0b001
8365 IrInstruction *is_suspended_mask = ir_build_const_usize(irb, parent_scope, node, 0x2); // 0b010
8366 IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0);
8367 IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, parent_scope, node, 0x7); // 0b111
8368 IrInstruction *ptr_mask = ir_build_un_op(irb, parent_scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000
8369
8370 IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, parent_scope, node,
8371 usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
8372 AtomicRmwOp_or, AtomicOrderSeqCst);
8373
8374 IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
8375 IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
8376 ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
8377
8378 ir_set_cursor_at_end_and_append_block(irb, canceled_block);
8379 IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
8380 IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
8381 IrBasicBlock *post_canceled_block = irb->current_basic_block;
8382 ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
8383
8384 ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
8385 IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
8386 ir_gen_cancel_target(irb, parent_scope, node, await_handle, true, false);
8387 IrBasicBlock *post_cancel_awaiter_block = irb->current_basic_block;
8388 ir_build_br(irb, parent_scope, node, cleanup_block, const_bool_false);
8389
8390 ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
8391 IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
8392 IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
8393 ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
8394
8395 ir_set_cursor_at_end_and_append_block(irb, suspended_block);
8396 ir_build_unreachable(irb, parent_scope, node);
8397
8398 ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
8399 IrInstruction *suspend_code;
8400 if (node->data.suspend.block == nullptr) {
8401 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false);
8402 } else {
8403 Scope *child_scope;
8404 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);7911 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
8405 suspend_scope->resume_block = resume_block;7912 Scope *child_scope = &suspend_scope->base;
8406 child_scope = &suspend_scope->base;7913 IrInstruction *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
8407 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);7914 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
8408 ir_gen_node(irb, node->data.suspend.block, child_scope);7915 }
8409 suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
8410 }
8411
8412 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8413 cases[0].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 0));
8414 cases[0].block = resume_block;
8415 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
8416 cases[1].block = canceled_block;
8417 IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, parent_scope, node, suspend_code,
8418 irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8419 ir_mark_gen(&switch_br->base);
8420
8421 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
8422 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8423 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8424 incoming_blocks[0] = post_canceled_block;
8425 incoming_values[0] = const_bool_true;
8426 incoming_blocks[1] = post_cancel_awaiter_block;
8427 incoming_values[1] = const_bool_false;
8428 IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values,
8429 nullptr);
8430 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
8431 ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
84327916
8433 ir_set_cursor_at_end_and_append_block(irb, resume_block);7917 return ir_mark_gen(ir_build_suspend_finish(irb, parent_scope, node, begin));
8434 return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
8435}7918}
84367919
8437static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,7920static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
...@@ -8523,8 +8006,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -8523,8 +8006,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
8523 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);8006 return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc);
8524 case NodeTypePointerType:8007 case NodeTypePointerType:
8525 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);8008 return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc);
8526 case NodeTypePromiseType:8009 case NodeTypeAnyFrameType:
8527 return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc);8010 return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc);
8528 case NodeTypeStringLiteral:8011 case NodeTypeStringLiteral:
8529 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);8012 return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc);
8530 case NodeTypeUndefinedLiteral:8013 case NodeTypeUndefinedLiteral:
...@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -8561,12 +8044,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
8561 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);8044 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc);
8562 case NodeTypeErrorSetDecl:8045 case NodeTypeErrorSetDecl:
8563 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc);8046 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc);
8564 case NodeTypeCancel:
8565 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc);
8566 case NodeTypeResume:8047 case NodeTypeResume:
8567 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);8048 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc);
8568 case NodeTypeAwaitExpr:8049 case NodeTypeAwaitExpr:
8569 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval, result_loc);8050 return ir_gen_await_expr(irb, scope, node, lval, result_loc);
8570 case NodeTypeSuspend:8051 case NodeTypeSuspend:
8571 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);8052 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc);
8572 case NodeTypeEnumLiteral:8053 case NodeTypeEnumLiteral:
...@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -8626,235 +8107,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
86268107
8627 irb->codegen = codegen;8108 irb->codegen = codegen;
8628 irb->exec = ir_executable;8109 irb->exec = ir_executable;
8110 irb->main_block_node = node;
86298111
8630 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");8112 IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry");
8631 ir_set_cursor_at_end_and_append_block(irb, entry_block);8113 ir_set_cursor_at_end_and_append_block(irb, entry_block);
8632 // Entry block gets a reference because we enter it to begin.8114 // Entry block gets a reference because we enter it to begin.
8633 ir_ref_bb(irb->current_basic_block);8115 ir_ref_bb(irb->current_basic_block);
86348116
8635 ZigFn *fn_entry = exec_fn_entry(irb->exec);
8636
8637 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
8638 IrInstruction *coro_id;
8639 IrInstruction *u8_ptr_type;
8640 IrInstruction *const_bool_false;
8641 IrInstruction *coro_promise_ptr;
8642 IrInstruction *err_ret_trace_ptr;
8643 ZigType *return_type;
8644 Buf *result_ptr_field_name;
8645 ZigVar *coro_size_var;
8646 if (is_async) {
8647 // create the coro promise
8648 Scope *coro_scope = create_coro_prelude_scope(irb->codegen, node, scope);
8649 const_bool_false = ir_build_const_bool(irb, coro_scope, node, false);
8650 ZigVar *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8651
8652 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
8653 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
8654 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
8655 ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
8656 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
8657 IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef, nullptr);
8658 build_decl_var_and_init(irb, coro_scope, node, promise_var, undef_coro_frame, "promise", const_bool_false);
8659 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
8660
8661 ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8662 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
8663 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
8664 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
8665 IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value, nullptr);
8666 build_decl_var_and_init(irb, coro_scope, node, await_handle_var, null_await_handle, "await_handle", const_bool_false);
8667 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
8668
8669 u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
8670 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
8671 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type,
8672 coro_promise_ptr, false);
8673 coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
8674 coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
8675 IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
8676 build_decl_var_and_init(irb, coro_scope, node, coro_size_var, coro_size, "coro_size", const_bool_false);
8677 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
8678 ImplicitAllocatorIdArg);
8679 irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
8680 build_decl_var_and_init(irb, coro_scope, node, irb->exec->coro_allocator_var, implicit_allocator_ptr,
8681 "allocator", const_bool_false);
8682 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);
8683 IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name, false);
8684 IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr);
8685 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, realloc_fn, coro_size);
8686 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
8687 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
8688 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
8689 ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
8690
8691 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
8692 // we can return undefined here, because the caller passes a pointer to the error struct field
8693 // in the error union result, and we populate it in case of allocation failure.
8694 ir_build_return(irb, coro_scope, node, undef);
8695
8696 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
8697 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr,
8698 false);
8699 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
8700
8701 Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
8702 irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
8703 atomic_state_field_name, false);
8704 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8705 ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
8706 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
8707 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false);
8708 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
8709 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false);
8710 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
8711 if (irb->codegen->have_err_ret_tracing) {
8712 // initialize the error return trace
8713 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
8714 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name, false);
8715
8716 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
8717 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false);
8718 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
8719
8720 // coordinate with builtin.zig
8721 Buf *index_name = buf_create_from_str("index");
8722 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name, false);
8723 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
8724
8725 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
8726 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false);
8727
8728 IrInstruction *slice_value = ir_build_slice_src(irb, scope, node, return_addresses_ptr, zero, nullptr, false, no_result_loc());
8729 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
8730 }
8731
8732
8733 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
8734 irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal");
8735 irb->exec->coro_suspend_block = ir_create_basic_block(irb, scope, "Suspend");
8736 irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
8737 }
8738
8739 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);8117 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr);
8740 assert(result);8118 assert(result);
8741 if (irb->exec->invalid)8119 if (irb->exec->invalid)
8742 return false;8120 return false;
87438121
8744 if (!instr_is_unreachable(result)) {8122 if (!instr_is_unreachable(result)) {
8123 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result));
8745 // no need for save_err_ret_addr because this cannot return error8124 // no need for save_err_ret_addr because this cannot return error
8746 ir_gen_async_return(irb, scope, result->source_node, result, true);8125 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
8747 }
8748
8749 if (is_async) {
8750 IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume");
8751 IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree");
8752
8753 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final);
8754 IrInstruction *const_bool_true = ir_build_const_bool(irb, scope, node, true);
8755 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, nullptr, const_bool_true);
8756 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
8757 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
8758 cases[0].block = invalid_resume_block;
8759 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
8760 cases[1].block = irb->exec->coro_final_cleanup_block;
8761 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
8762
8763 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
8764 ir_build_coro_end(irb, scope, node);
8765 ir_build_return(irb, scope, node, irb->exec->coro_handle);
8766
8767 ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block);
8768 ir_build_unreachable(irb, scope, node);
8769
8770 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
8771 if (type_has_bits(return_type)) {
8772 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8773 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8774 false, false, PtrLenUnknown, 0, 0, 0, false));
8775 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
8776 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8777 result_ptr, false);
8778 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node,
8779 u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false);
8780 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
8781 fn_entry->type_entry->data.fn.fn_type_id.return_type);
8782 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
8783 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
8784 }
8785 if (irb->codegen->have_err_ret_tracing) {
8786 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
8787 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false);
8788 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
8789 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
8790 }
8791 // Before we destroy the coroutine frame, we need to load the target promise into
8792 // a register or local variable which does not get spilled into the frame,
8793 // otherwise llvm tries to access memory inside the destroyed frame.
8794 IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
8795 irb->exec->await_handle_var_ptr, false, false);
8796 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
8797 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8798
8799 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
8800 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
8801
8802 ir_set_cursor_at_end_and_append_block(irb, check_free_block);
8803 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8804 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8805 incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8806 incoming_values[0] = const_bool_false;
8807 incoming_blocks[1] = irb->exec->coro_normal_final;
8808 incoming_values[1] = const_bool_true;
8809 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr);
8810
8811 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
8812 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
8813 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
8814 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
8815 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
8816 merge_incoming_values[1] = await_handle_in_block;
8817 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values, nullptr);
8818
8819 Buf *shrink_field_name = buf_create_from_str(ASYNC_SHRINK_FIELD_NAME);
8820 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
8821 ImplicitAllocatorIdLocalVar);
8822 IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name, false);
8823 IrInstruction *shrink_fn = ir_build_load_ptr(irb, scope, node, shrink_fn_ptr);
8824 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
8825 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
8826 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
8827 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
8828 false, false, PtrLenUnknown, 0, 0, 0, false));
8829 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
8830 coro_mem_ptr_maybe, false);
8831 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
8832 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
8833 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
8834 IrInstruction *mem_slice = ir_build_slice_src(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
8835 no_result_loc());
8836 size_t arg_count = 5;
8837 IrInstruction **args = allocate<IrInstruction *>(arg_count);
8838 args[0] = implicit_allocator_ptr; // self
8839 args[1] = mem_slice; // old_mem
8840 args[2] = ir_build_const_usize(irb, scope, node, 8); // old_align
8841 // TODO: intentional memory leak here. If this is set to 0 then there is an issue where a coroutine
8842 // calls the function and it frees its own stack frame, but then the return value is a slice, which
8843 // is implemented as an sret struct. writing to the return pointer causes invalid memory write.
8844 // We could work around it by having a global helper function which has a void return type
8845 // and calling that instead. But instead this hack will suffice until I rework coroutines to be
8846 // non-allocating. Basically coroutines are not supported right now until they are reworked.
8847 args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size
8848 args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align
8849 ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr,
8850 nullptr, no_result_loc());
8851
8852 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
8853 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
8854
8855 ir_set_cursor_at_end_and_append_block(irb, resume_block);
8856 ir_gen_resume_target(irb, scope, node, awaiter_handle);
8857 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
8858 }8126 }
88598127
8860 return true;8128 return true;
...@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {...@@ -8871,18 +8139,24 @@ bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
8871 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);8139 return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable);
8872}8140}
88738141
8874static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {8142static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg *err_msg, int limit) {
8875 if (!exec || !exec->source_node || limit < 0) return;8143 if (!exec || !exec->source_node || limit < 0) return;
8876 add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));8144 add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here"));
88778145
8878 add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);8146 ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1);
8147}
8148
8149void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) {
8150 IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
8151 add_error_note(ira->codegen, err_msg, old_instruction->source_node, text);
8152 ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10);
8879}8153}
88808154
8881static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {8155static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
8882 invalidate_exec(exec);8156 invalidate_exec(exec);
8883 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);8157 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
8884 if (exec->parent_exec) {8158 if (exec->parent_exec) {
8885 add_call_stack_errors(codegen, exec, err_msg, 10);8159 ir_add_call_stack_errors(codegen, exec, err_msg, 10);
8886 }8160 }
8887 return err_msg;8161 return err_msg;
8888}8162}
...@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec...@@ -8946,13 +8220,13 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec
8946 IrInstruction *instruction = bb->instruction_list.at(i);8220 IrInstruction *instruction = bb->instruction_list.at(i);
8947 if (instruction->id == IrInstructionIdReturn) {8221 if (instruction->id == IrInstructionIdReturn) {
8948 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;8222 IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction;
8949 IrInstruction *value = ret_inst->value;8223 IrInstruction *operand = ret_inst->operand;
8950 if (value->value.special == ConstValSpecialRuntime) {8224 if (operand->value.special == ConstValSpecialRuntime) {
8951 exec_add_error_node(codegen, exec, value->source_node,8225 exec_add_error_node(codegen, exec, operand->source_node,
8952 buf_sprintf("unable to evaluate constant expression"));8226 buf_sprintf("unable to evaluate constant expression"));
8953 return &codegen->invalid_instruction->value;8227 return &codegen->invalid_instruction->value;
8954 }8228 }
8955 return &value->value;8229 return &operand->value;
8956 } else if (ir_has_side_effects(instruction)) {8230 } else if (ir_has_side_effects(instruction)) {
8957 if (instr_is_comptime(instruction)) {8231 if (instr_is_comptime(instruction)) {
8958 switch (instruction->id) {8232 switch (instruction->id) {
...@@ -9713,6 +8987,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc...@@ -9713,6 +8987,9 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
9713 bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat);8987 bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat);
9714 assert(const_val_is_int || const_val_is_float);8988 assert(const_val_is_int || const_val_is_float);
97158989
8990 if (const_val_is_int && other_type->id == ZigTypeIdComptimeFloat) {
8991 return true;
8992 }
9716 if (other_type->id == ZigTypeIdFloat) {8993 if (other_type->id == ZigTypeIdFloat) {
9717 if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) {8994 if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) {
9718 return true;8995 return true;
...@@ -10200,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -10200,12 +9477,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
10200 return result;9477 return result;
10201 }9478 }
102029479
10203 if (wanted_type == ira->codegen->builtin_types.entry_promise &&
10204 actual_type->id == ZigTypeIdPromise)
10205 {
10206 return result;
10207 }
10208
10209 // fn9480 // fn
10210 if (wanted_type->id == ZigTypeIdFn &&9481 if (wanted_type->id == ZigTypeIdFn &&
10211 actual_type->id == ZigTypeIdFn)9482 actual_type->id == ZigTypeIdFn)
...@@ -10240,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -10240,20 +9511,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
10240 return result;9511 return result;
10241 }9512 }
10242 }9513 }
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 }
10257 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {9514 if (wanted_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
10258 result.id = ConstCastResultIdFnArgCount;9515 result.id = ConstCastResultIdFnArgCount;
10259 return result;9516 return result;
...@@ -10358,6 +9615,10 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT...@@ -10358,6 +9615,10 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
10358 return cur_type;9615 return cur_type;
10359 }9616 }
103609617
9618 if (prev_type == cur_type) {
9619 continue;
9620 }
9621
10361 if (prev_type->id == ZigTypeIdUnreachable) {9622 if (prev_type->id == ZigTypeIdUnreachable) {
10362 prev_inst = cur_inst;9623 prev_inst = cur_inst;
10363 continue;9624 continue;
...@@ -10558,6 +9819,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT...@@ -10558,6 +9819,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
105589819
10559 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;9820 ZigType *prev_err_set_type = (err_set_type == nullptr) ? prev_type->data.error_union.err_set_type : err_set_type;
10560 ZigType *cur_err_set_type = cur_type->data.error_union.err_set_type;9821 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
10562 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {9825 if (!resolve_inferred_error_set(ira->codegen, prev_err_set_type, cur_inst->source_node)) {
10563 return ira->codegen->builtin_types.entry_invalid;9826 return ira->codegen->builtin_types.entry_invalid;
...@@ -11203,7 +10466,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,...@@ -11203,7 +10466,7 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb,
11203}10466}
1120410467
11205static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) {10468static 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);
11207 ira->instruction_index = 0;10470 ira->instruction_index = 0;
11208 ira->old_irb.current_basic_block = old_bb;10471 ira->old_irb.current_basic_block = old_bb;
11209 ira->const_predecessor_bb = const_predecessor_bb;10472 ira->const_predecessor_bb = const_predecessor_bb;
...@@ -11726,6 +10989,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou...@@ -11726,6 +10989,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
11726 return result;10989 return result;
11727}10990}
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
11729static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,11019static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
11730 ZigType *wanted_type, ResultLoc *result_loc)11020 ZigType *wanted_type, ResultLoc *result_loc)
11731{11021{
...@@ -11935,7 +11225,6 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour...@@ -11935,7 +11225,6 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
11935 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&11225 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
11936 enum_type->data.enumeration.src_field_count == 1)11226 enum_type->data.enumeration.src_field_count == 1)
11937 {11227 {
11938 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
11939 IrInstruction *result = ir_const(ira, source_instr, tag_type);11228 IrInstruction *result = ir_const(ira, source_instr, tag_type);
11940 init_const_bigint(&result->value, tag_type,11229 init_const_bigint(&result->value, tag_type,
11941 &enum_type->data.enumeration.fields[0].value);11230 &enum_type->data.enumeration.fields[0].value);
...@@ -12574,12 +11863,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou...@@ -12574,12 +11863,10 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou
12574static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {11863static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {
12575 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;11864 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;
12576 if (ty->id == ZigTypeIdFn) return true;11865 if (ty->id == ZigTypeIdFn) return true;
12577 if (ty->id == ZigTypeIdPromise) return true;
12578 if (ty->id == ZigTypeIdOptional) {11866 if (ty->id == ZigTypeIdOptional) {
12579 ZigType *ptr_ty = ty->data.maybe.child_type;11867 ZigType *ptr_ty = ty->data.maybe.child_type;
12580 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;11868 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;
12581 if (ptr_ty->id == ZigTypeIdFn) return true;11869 if (ptr_ty->id == ZigTypeIdFn) return true;
12582 if (ptr_ty->id == ZigTypeIdPromise) return true;
12583 }11870 }
12584 return false;11871 return false;
12585}11872}
...@@ -12827,6 +12114,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -12827,6 +12114,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
12827 }12114 }
12828 }12115 }
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
12831 // cast from null literal to maybe type12142 // cast from null literal to maybe type
12832 if (wanted_type->id == ZigTypeIdOptional &&12143 if (wanted_type->id == ZigTypeIdOptional &&
...@@ -13331,11 +12642,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze...@@ -13331,11 +12642,11 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze
13331}12642}
1333212643
13333static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {12644static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) {
13334 IrInstruction *value = instruction->value->child;12645 IrInstruction *operand = instruction->operand->child;
13335 if (type_is_invalid(value->value.type))12646 if (type_is_invalid(operand->value.type))
13336 return ir_unreach_error(ira);12647 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)) {
13339 // result location mechanism took care of it.12650 // result location mechanism took care of it.
13340 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,12651 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
13341 instruction->base.source_node, nullptr);12652 instruction->base.source_node, nullptr);
...@@ -13343,8 +12654,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio...@@ -13343,8 +12654,8 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
13343 return ir_finish_anal(ira, result);12654 return ir_finish_anal(ira, result);
13344 }12655 }
1334512656
13346 IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);12657 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type);
13347 if (type_is_invalid(casted_value->value.type)) {12658 if (type_is_invalid(casted_operand->value.type)) {
13348 AstNode *source_node = ira->explicit_return_type_source_node;12659 AstNode *source_node = ira->explicit_return_type_source_node;
13349 if (source_node != nullptr) {12660 if (source_node != nullptr) {
13350 ErrorMsg *msg = ira->codegen->errors.last();12661 ErrorMsg *msg = ira->codegen->errors.last();
...@@ -13354,15 +12665,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio...@@ -13354,15 +12665,16 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
13354 return ir_unreach_error(ira);12665 return ir_unreach_error(ira);
13355 }12666 }
1335612667
13357 if (casted_value->value.special == ConstValSpecialRuntime &&12668 if (casted_operand->value.special == ConstValSpecialRuntime &&
13358 casted_value->value.type->id == ZigTypeIdPointer &&12669 casted_operand->value.type->id == ZigTypeIdPointer &&
13359 casted_value->value.data.rh_ptr == RuntimeHintPtrStack)12670 casted_operand->value.data.rh_ptr == RuntimeHintPtrStack)
13360 {12671 {
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"));
13362 return ir_unreach_error(ira);12673 return ir_unreach_error(ira);
13363 }12674 }
12675
13364 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,12676 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);
13366 result->value.type = ira->codegen->builtin_types.entry_unreachable;12678 result->value.type = ira->codegen->builtin_types.entry_unreachable;
13367 return ir_finish_anal(ira, result);12679 return ir_finish_anal(ira, result);
13368}12680}
...@@ -13656,9 +12968,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13656,9 +12968,9 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13656 case ZigTypeIdOpaque:12968 case ZigTypeIdOpaque:
13657 case ZigTypeIdBoundFn:12969 case ZigTypeIdBoundFn:
13658 case ZigTypeIdArgTuple:12970 case ZigTypeIdArgTuple:
13659 case ZigTypeIdPromise:
13660 case ZigTypeIdEnum:12971 case ZigTypeIdEnum:
13661 case ZigTypeIdEnumLiteral:12972 case ZigTypeIdEnumLiteral:
12973 case ZigTypeIdAnyFrame:
13662 operator_allowed = is_equality_cmp;12974 operator_allowed = is_equality_cmp;
13663 break;12975 break;
1366412976
...@@ -13673,6 +12985,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *...@@ -13673,6 +12985,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
13673 case ZigTypeIdNull:12985 case ZigTypeIdNull:
13674 case ZigTypeIdErrorUnion:12986 case ZigTypeIdErrorUnion:
13675 case ZigTypeIdUnion:12987 case ZigTypeIdUnion:
12988 case ZigTypeIdFnFrame:
13676 operator_allowed = false;12989 operator_allowed = false;
13677 break;12990 break;
13678 case ZigTypeIdOptional:12991 case ZigTypeIdOptional:
...@@ -15037,7 +14350,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -15037,7 +14350,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
15037 case ZigTypeIdBoundFn:14350 case ZigTypeIdBoundFn:
15038 case ZigTypeIdArgTuple:14351 case ZigTypeIdArgTuple:
15039 case ZigTypeIdOpaque:14352 case ZigTypeIdOpaque:
15040 case ZigTypeIdPromise:14353 case ZigTypeIdFnFrame:
14354 case ZigTypeIdAnyFrame:
15041 ir_add_error(ira, target,14355 ir_add_error(ira, target,
15042 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));14356 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));
15043 break;14357 break;
...@@ -15061,8 +14375,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -15061,8 +14375,9 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
15061 case ZigTypeIdBoundFn:14375 case ZigTypeIdBoundFn:
15062 case ZigTypeIdArgTuple:14376 case ZigTypeIdArgTuple:
15063 case ZigTypeIdOpaque:14377 case ZigTypeIdOpaque:
15064 case ZigTypeIdPromise:
15065 case ZigTypeIdEnumLiteral:14378 case ZigTypeIdEnumLiteral:
14379 case ZigTypeIdFnFrame:
14380 case ZigTypeIdAnyFrame:
15066 ir_add_error(ira, target,14381 ir_add_error(ira, target,
15067 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));14382 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));
15068 break;14383 break;
...@@ -15089,8 +14404,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {...@@ -15089,8 +14404,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
15089static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,14404static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
15090 IrInstructionErrorReturnTrace *instruction)14405 IrInstructionErrorReturnTrace *instruction)
15091{14406{
14407 ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false);
15092 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {14408 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
15093 ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
15094 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);14409 ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
15095 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {14410 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
15096 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);14411 IrInstruction *result = ir_const(ira, &instruction->base, optional_type);
...@@ -15108,7 +14423,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,...@@ -15108,7 +14423,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
15108 assert(ira->codegen->have_err_ret_tracing);14423 assert(ira->codegen->have_err_ret_tracing);
15109 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,14424 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
15110 instruction->base.source_node, instruction->optional);14425 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;
15112 return new_instruction;14427 return new_instruction;
15113 }14428 }
15114}14429}
...@@ -15140,42 +14455,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,...@@ -15140,42 +14455,6 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
15140 return ir_const_type(ira, &instruction->base, result_type);14455 return ir_const_type(ira, &instruction->base, result_type);
15141}14456}
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
15179static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,14458static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,
15180 uint32_t align, const char *name_hint, bool force_comptime)14459 uint32_t align, const char *name_hint, bool force_comptime)
15181{14460{
...@@ -15184,7 +14463,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in...@@ -15184,7 +14463,7 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in
15184 ConstExprValue *pointee = create_const_vals(1);14463 ConstExprValue *pointee = create_const_vals(1);
15185 pointee->special = ConstValSpecialUndef;14464 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);
15188 result->base.value.special = ConstValSpecialStatic;14467 result->base.value.special = ConstValSpecialStatic;
15189 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;14468 result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
15190 result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer;14469 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...@@ -15281,7 +14560,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
15281 return nullptr;14560 return nullptr;
15282 }14561 }
15283 // need to return a result location and don't have one. use a stack allocation14562 // 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, "");
15285 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))14564 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown)))
15286 return ira->codegen->invalid_instruction;14565 return ira->codegen->invalid_instruction;
15287 alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false,14566 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...@@ -15351,8 +14630,12 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
15351 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {14630 if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) {
15352 return ira->codegen->invalid_instruction;14631 return ira->codegen->invalid_instruction;
15353 }14632 }
15354 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type))14633 if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) {
15355 return nullptr;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
15357 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);14640 ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false);
15358 result_loc->written = true;14641 result_loc->written = true;
...@@ -15614,48 +14897,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst...@@ -15614,48 +14897,43 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
1561414897
15615static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,14898static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
15616 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,14899 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
15617 IrInstruction *async_allocator_inst)14900 IrInstruction *casted_new_stack)
15618{14901{
15619 Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME);14902 if (casted_new_stack != nullptr) {
15620 ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base);14903 // this is an @asyncCall
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);
1562914904
15630 ZigType *realloc_fn_type = ptr_to_realloc_fn_type->data.pointer.child_type;14905 if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
15631 if (realloc_fn_type->id != ZigTypeIdFn) {14906 ir_add_error(ira, fn_ref,
15632 ir_add_error(ira, &call_instruction->base,14907 buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
15633 buf_sprintf("expected reallocation function, found '%s'", buf_ptr(&realloc_fn_type->name)));14908 return ira->codegen->invalid_instruction;
15634 return ira->codegen->invalid_instruction;14909 }
15635 }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;14915 ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type);
15638 if (realloc_fn_return_type->id != ZigTypeIdErrorUnion) {14916
15639 ir_add_error(ira, fn_ref,14917 IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
15640 buf_sprintf("expected allocation function to return error union, but it returns '%s'", buf_ptr(&realloc_fn_return_type->name)));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"));
15641 return ira->codegen->invalid_instruction;14922 return ira->codegen->invalid_instruction;
15642 }14923 }
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(),14925 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry);
15649 async_return_type, nullptr, true, true, false);14926 IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
14927 frame_type, nullptr, true, true, false);
15650 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {14928 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
15651 return result_loc;14929 return result_loc;
15652 }14930 }
1565314931 result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
15654 return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,14932 if (type_is_invalid(result_loc->value.type))
15655 casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc,14933 return ira->codegen->invalid_instruction;
15656 async_return_type);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;
15657}14936}
15658
15659static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,14937static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
15660 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)14938 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
15661{14939{
...@@ -16002,20 +15280,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16002,20 +15280,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16002 }15280 }
16003 return ira->codegen->invalid_instruction;15281 return ira->codegen->invalid_instruction;
16004 }15282 }
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
16021 if (fn_type_id->is_var_args) {15285 if (fn_type_id->is_var_args) {
...@@ -16352,33 +15616,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16352,33 +15616,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16352 break;15616 break;
16353 }15617 }
16354 }15618 }
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
16383 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);15620 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
16384 if (existing_entry) {15621 if (existing_entry) {
...@@ -16405,11 +15642,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16405,11 +15642,15 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16405 if (handle_is_ptr(impl_fn_type_id->return_type)) {15642 if (handle_is_ptr(impl_fn_type_id->return_type)) {
16406 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,15643 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
16407 impl_fn_type_id->return_type, nullptr, true, true, false);15644 impl_fn_type_id->return_type, nullptr, true, true, false);
16408 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||15645 if (result_loc != nullptr) {
16409 instr_is_unreachable(result_loc)))15646 if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
16410 {15647 return result_loc;
16411 return result_loc;15648 }
16412 }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 }
16413 } else {15654 } else {
16414 result_loc = nullptr;15655 result_loc = nullptr;
16415 }15656 }
...@@ -16421,17 +15662,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16421,17 +15662,23 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16421 size_t impl_param_count = impl_fn_type_id->param_count;15662 size_t impl_param_count = impl_fn_type_id->param_count;
16422 if (call_instruction->is_async) {15663 if (call_instruction->is_async) {
16423 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,15664 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);
16425 return ir_finish_anal(ira, result);15666 return ir_finish_anal(ira, result);
16426 }15667 }
1642715668
16428 assert(async_allocator_inst == nullptr);15669 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
16429 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,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,
16430 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,15675 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,
16432 impl_fn_type_id->return_type);15677 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);
16435 }15682 }
1643615683
16437 ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);15684 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...@@ -16473,20 +15720,56 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16473 IrInstruction *old_arg = call_instruction->args[call_i]->child;15720 IrInstruction *old_arg = call_instruction->args[call_i]->child;
16474 if (type_is_invalid(old_arg->value.type))15721 if (type_is_invalid(old_arg->value.type))
16475 return ira->codegen->invalid_instruction;15722 return ira->codegen->invalid_instruction;
16476 IrInstruction *casted_arg;15723
16477 if (next_arg_index < src_param_count) {15724 if (old_arg->value.type->id == ZigTypeIdArgTuple) {
16478 ZigType *param_type = fn_type_id->param_info[next_arg_index].type;15725 for (size_t arg_tuple_i = old_arg->value.data.x_arg_tuple.start_index;
16479 if (type_is_invalid(param_type))15726 arg_tuple_i < old_arg->value.data.x_arg_tuple.end_index; arg_tuple_i += 1)
16480 return ira->codegen->invalid_instruction;15727 {
16481 casted_arg = ir_implicit_cast(ira, old_arg, param_type);15728 ZigVar *arg_var = get_fn_var_by_index(parent_fn_entry, arg_tuple_i);
16482 if (type_is_invalid(casted_arg->value.type))15729 if (arg_var == nullptr) {
16483 return ira->codegen->invalid_instruction;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 }
16484 } else {15757 } else {
16485 casted_arg = old_arg;15758 IrInstruction *casted_arg;
16486 }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;15770 casted_args[next_arg_index] = casted_arg;
16489 next_arg_index += 1;15771 next_arg_index += 1;
15772 }
16490 }15773 }
1649115774
16492 assert(next_arg_index == call_param_count);15775 assert(next_arg_index == call_param_count);
...@@ -16495,49 +15778,45 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -16495,49 +15778,45 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
16495 if (type_is_invalid(return_type))15778 if (type_is_invalid(return_type))
16496 return ira->codegen->invalid_instruction;15779 return ira->codegen->invalid_instruction;
1649715780
16498 if (call_instruction->is_async) {15781 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {
16499 IrInstruction *uncasted_async_allocator_inst;15782 ir_add_error(ira, &call_instruction->base,
16500 if (call_instruction->async_allocator == nullptr) {15783 buf_sprintf("no-inline call of inline function"));
16501 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,15784 return ira->codegen->invalid_instruction;
16502 ImplicitAllocatorIdLocalVar);15785 }
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;
1651415786
15787 if (call_instruction->is_async) {
16515 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,15788 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);
16517 return ir_finish_anal(ira, result);15790 return ir_finish_anal(ira, result);
16518 }15791 }
1651915792
16520 if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) {15793 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
16521 ir_add_error(ira, &call_instruction->base,15794 parent_fn_entry->inferred_async_node = fn_ref->source_node;
16522 buf_sprintf("no-inline call of inline function"));15795 parent_fn_entry->inferred_async_fn = fn_entry;
16523 return ira->codegen->invalid_instruction;
16524 }15796 }
1652515797
16526 IrInstruction *result_loc;15798 IrInstruction *result_loc;
16527 if (handle_is_ptr(return_type)) {15799 if (handle_is_ptr(return_type)) {
16528 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,15800 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
16529 return_type, nullptr, true, true, false);15801 return_type, nullptr, true, true, false);
16530 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {15802 if (result_loc != nullptr) {
16531 return result_loc;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 }
16532 }15810 }
16533 } else {15811 } else {
16534 result_loc = nullptr;15812 result_loc = nullptr;
16535 }15813 }
1653615814
16537 IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,15815 IrInstructionCallGen *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,15816 call_param_count, casted_args, fn_inline, false, casted_new_stack,
16539 result_loc, return_type);15817 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);
16541}15820}
1654215821
16543static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) {15822static 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...@@ -16682,7 +15961,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
16682 zig_unreachable();15961 zig_unreachable();
16683}15962}
1668415963
16685static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {15964static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
16686 Error err;15965 Error err;
16687 IrInstruction *value = un_op_instruction->value->child;15966 IrInstruction *value = un_op_instruction->value->child;
16688 ZigType *type_entry = ir_resolve_type(ira, value);15967 ZigType *type_entry = ir_resolve_type(ira, value);
...@@ -16716,8 +15995,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_...@@ -16716,8 +15995,10 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
16716 case ZigTypeIdFn:15995 case ZigTypeIdFn:
16717 case ZigTypeIdBoundFn:15996 case ZigTypeIdBoundFn:
16718 case ZigTypeIdArgTuple:15997 case ZigTypeIdArgTuple:
16719 case ZigTypeIdPromise:15998 case ZigTypeIdFnFrame:
15999 case ZigTypeIdAnyFrame:
16720 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));16000 return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry));
16001
16721 case ZigTypeIdUnreachable:16002 case ZigTypeIdUnreachable:
16722 case ZigTypeIdOpaque:16003 case ZigTypeIdOpaque:
16723 ir_add_error_node(ira, un_op_instruction->base.source_node,16004 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...@@ -16881,7 +16162,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
16881 return result;16162 return result;
16882 }16163 }
16883 case IrUnOpOptional:16164 case IrUnOpOptional:
16884 return ir_analyze_maybe(ira, instruction);16165 return ir_analyze_optional_type(ira, instruction);
16885 }16166 }
16886 zig_unreachable();16167 zig_unreachable();
16887}16168}
...@@ -18441,6 +17722,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,...@@ -18441,6 +17722,20 @@ static IrInstruction *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
18441 return ir_const_void(ira, &instruction->base);17722 return ir_const_void(ira, &instruction->base);
18442}17723}
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
18444static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,17739static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
18445 IrInstructionSliceType *slice_type_instruction)17740 IrInstructionSliceType *slice_type_instruction)
18446{17741{
...@@ -18488,8 +17783,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -18488,8 +17783,9 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
18488 case ZigTypeIdUnion:17783 case ZigTypeIdUnion:
18489 case ZigTypeIdFn:17784 case ZigTypeIdFn:
18490 case ZigTypeIdBoundFn:17785 case ZigTypeIdBoundFn:
18491 case ZigTypeIdPromise:
18492 case ZigTypeIdVector:17786 case ZigTypeIdVector:
17787 case ZigTypeIdFnFrame:
17788 case ZigTypeIdAnyFrame:
18493 {17789 {
18494 ResolveStatus needed_status = (align_bytes == 0) ?17790 ResolveStatus needed_status = (align_bytes == 0) ?
18495 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;17791 ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown;
...@@ -18603,8 +17899,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -18603,8 +17899,9 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
18603 case ZigTypeIdUnion:17899 case ZigTypeIdUnion:
18604 case ZigTypeIdFn:17900 case ZigTypeIdFn:
18605 case ZigTypeIdBoundFn:17901 case ZigTypeIdBoundFn:
18606 case ZigTypeIdPromise:
18607 case ZigTypeIdVector:17902 case ZigTypeIdVector:
17903 case ZigTypeIdFnFrame:
17904 case ZigTypeIdAnyFrame:
18608 {17905 {
18609 if ((err = ensure_complete_type(ira->codegen, child_type)))17906 if ((err = ensure_complete_type(ira->codegen, child_type)))
18610 return ira->codegen->invalid_instruction;17907 return ira->codegen->invalid_instruction;
...@@ -18615,22 +17912,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,...@@ -18615,22 +17912,6 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
18615 zig_unreachable();17912 zig_unreachable();
18616}17913}
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
18634static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,17915static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
18635 IrInstructionSizeOf *size_of_instruction)17916 IrInstructionSizeOf *size_of_instruction)
18636{17917{
...@@ -18670,8 +17951,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -18670,8 +17951,9 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
18670 case ZigTypeIdEnum:17951 case ZigTypeIdEnum:
18671 case ZigTypeIdUnion:17952 case ZigTypeIdUnion:
18672 case ZigTypeIdFn:17953 case ZigTypeIdFn:
18673 case ZigTypeIdPromise:
18674 case ZigTypeIdVector:17954 case ZigTypeIdVector:
17955 case ZigTypeIdFnFrame:
17956 case ZigTypeIdAnyFrame:
18675 {17957 {
18676 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);17958 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
18677 return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);17959 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,...@@ -19157,7 +18439,6 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
19157 case ZigTypeIdComptimeInt:18439 case ZigTypeIdComptimeInt:
19158 case ZigTypeIdEnumLiteral:18440 case ZigTypeIdEnumLiteral:
19159 case ZigTypeIdPointer:18441 case ZigTypeIdPointer:
19160 case ZigTypeIdPromise:
19161 case ZigTypeIdFn:18442 case ZigTypeIdFn:
19162 case ZigTypeIdErrorSet: {18443 case ZigTypeIdErrorSet: {
19163 if (pointee_val) {18444 if (pointee_val) {
...@@ -19236,6 +18517,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -19236,6 +18517,8 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
19236 case ZigTypeIdArgTuple:18517 case ZigTypeIdArgTuple:
19237 case ZigTypeIdOpaque:18518 case ZigTypeIdOpaque:
19238 case ZigTypeIdVector:18519 case ZigTypeIdVector:
18520 case ZigTypeIdFnFrame:
18521 case ZigTypeIdAnyFrame:
19239 ir_add_error(ira, &switch_target_instruction->base,18522 ir_add_error(ira, &switch_target_instruction->base,
19240 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));18523 buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
19241 return ira->codegen->invalid_instruction;18524 return ira->codegen->invalid_instruction;
...@@ -20670,32 +19953,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -20670,32 +19953,22 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2067019953
20671 break;19954 break;
20672 }19955 }
20673 case ZigTypeIdPromise:19956 case ZigTypeIdAnyFrame: {
20674 {19957 result = create_const_vals(1);
20675 result = create_const_vals(1);19958 result->special = ConstValSpecialStatic;
20676 result->special = ConstValSpecialStatic;19959 result->type = ir_type_info_get_type(ira, "AnyFrame", nullptr);
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);
2068619960
20687 if (type_entry->data.promise.result_type == nullptr)19961 ConstExprValue *fields = create_const_vals(1);
20688 fields[0].data.x_optional = nullptr;19962 result->data.x_struct.fields = fields;
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 }
2069619963
20697 break;19964 // child: ?type
20698 }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 }
20699 case ZigTypeIdEnum:19972 case ZigTypeIdEnum:
20700 {19973 {
20701 result = create_const_vals(1);19974 result = create_const_vals(1);
...@@ -21005,7 +20278,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -21005,7 +20278,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21005 result->special = ConstValSpecialStatic;20278 result->special = ConstValSpecialStatic;
21006 result->type = ir_type_info_get_type(ira, "Fn", nullptr);20279 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);
21009 result->data.x_struct.fields = fields;20282 result->data.x_struct.fields = fields;
2101020283
21011 // calling_convention: TypeInfo.CallingConvention20284 // calling_convention: TypeInfo.CallingConvention
...@@ -21038,19 +20311,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr...@@ -21038,19 +20311,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21038 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;20311 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
21039 fields[3].data.x_optional = return_type;20312 fields[3].data.x_optional = return_type;
21040 }20313 }
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 }
21054 // args: []TypeInfo.FnArg20314 // args: []TypeInfo.FnArg
21055 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);20315 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);
21056 if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) {20316 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...@@ -21065,10 +20325,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
21065 fn_arg_array->data.x_array.special = ConstArraySpecialNone;20325 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
21066 fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);20326 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++)20330 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
21071 {
21072 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];20331 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
21073 ConstExprValue *fn_arg_val = &fn_arg_array->data.x_array.data.s_none.elements[fn_arg_index];20332 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...@@ -21115,6 +20374,8 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
2111520374
21116 break;20375 break;
21117 }20376 }
20377 case ZigTypeIdFnFrame:
20378 zig_panic("TODO @typeInfo for async function frames");
21118 }20379 }
2111920380
21120 assert(result != nullptr);20381 assert(result != nullptr);
...@@ -21312,12 +20573,15 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct...@@ -21312,12 +20573,15 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
21312 }20573 }
21313 for (size_t i = 0; i < errors_len; i += 1) {20574 for (size_t i = 0; i < errors_len; i += 1) {
21314 Stage2ErrorMsg *clang_err = &errors_ptr[i];20575 Stage2ErrorMsg *clang_err = &errors_ptr[i];
21315 ErrorMsg *err_msg = err_msg_create_with_offset(20576 // Clang can emit "too many errors, stopping now", in which case `source` and `filename_ptr` are null
21316 clang_err->filename_ptr ?20577 if (clang_err->source && clang_err->filename_ptr) {
21317 buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),20578 ErrorMsg *err_msg = err_msg_create_with_offset(
21318 clang_err->line, clang_err->column, clang_err->offset, clang_err->source,20579 clang_err->filename_ptr ?
21319 buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));20580 buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
21320 err_msg_add_note(parent_err_msg, err_msg);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 }
21321 }20585 }
2132220586
21323 return ira->codegen->invalid_instruction;20587 return ira->codegen->invalid_instruction;
...@@ -22825,11 +22089,51 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns...@@ -22825,11 +22089,51 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns
22825 return result;22089 return result;
22826}22090}
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
22829 IrInstruction *result = ir_build_handle(&ira->new_irb, instruction->base.scope, instruction->base.source_node);22103 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);22104 result->value.type = ptr_frame_type;
22831 assert(fn_entry != nullptr);22105 return result;
22832 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);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;
22833 return result;22137 return result;
22834}22138}
2283522139
...@@ -22864,7 +22168,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -22864,7 +22168,6 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
22864 case ZigTypeIdInt:22168 case ZigTypeIdInt:
22865 case ZigTypeIdFloat:22169 case ZigTypeIdFloat:
22866 case ZigTypeIdPointer:22170 case ZigTypeIdPointer:
22867 case ZigTypeIdPromise:
22868 case ZigTypeIdArray:22171 case ZigTypeIdArray:
22869 case ZigTypeIdStruct:22172 case ZigTypeIdStruct:
22870 case ZigTypeIdOptional:22173 case ZigTypeIdOptional:
...@@ -22874,6 +22177,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -22874,6 +22177,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
22874 case ZigTypeIdUnion:22177 case ZigTypeIdUnion:
22875 case ZigTypeIdFn:22178 case ZigTypeIdFn:
22876 case ZigTypeIdVector:22179 case ZigTypeIdVector:
22180 case ZigTypeIdFnFrame:
22181 case ZigTypeIdAnyFrame:
22877 {22182 {
22878 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);22183 uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
22879 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);22184 return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
...@@ -22988,19 +22293,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr...@@ -22988,19 +22293,6 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
22988 return result;22293 return result;
22989}22294}
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
23004static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,22296static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,
23005 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {22297 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {
23006 if (float_type->id == ZigTypeIdComptimeFloat) {22298 if (float_type->id == ZigTypeIdComptimeFloat) {
...@@ -23125,11 +22417,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct...@@ -23125,11 +22417,16 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
23125 if (type_is_invalid(base_ptr->value.type))22417 if (type_is_invalid(base_ptr->value.type))
23126 return ira->codegen->invalid_instruction;22418 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
23129 ZigType *type_entry = value->value.type;22427 ZigType *type_entry = value->value.type;
23130 if (type_is_invalid(type_entry))22428 if (type_is_invalid(type_entry))
23131 return ira->codegen->invalid_instruction;22429 return ira->codegen->invalid_instruction;
23132
23133 if (type_entry->id == ZigTypeIdErrorUnion) {22430 if (type_entry->id == ZigTypeIdErrorUnion) {
23134 if (instr_is_comptime(value)) {22431 if (instr_is_comptime(value)) {
23135 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);22432 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
...@@ -23423,18 +22720,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct...@@ -23423,18 +22720,6 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
23423 return ira->codegen->invalid_instruction;22720 return ira->codegen->invalid_instruction;
23424 }22721 }
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
23438 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));22723 return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id));
23439}22724}
2344022725
...@@ -23673,7 +22958,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *...@@ -23673,7 +22958,7 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
23673 if (type_is_invalid(statement_type))22958 if (type_is_invalid(statement_type))
23674 return ira->codegen->invalid_instruction;22959 return ira->codegen->invalid_instruction;
2367522960
23676 if (statement_type->id != ZigTypeIdVoid) {22961 if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) {
23677 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));22962 ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
23678 }22963 }
2367922964
...@@ -23928,7 +23213,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -23928,7 +23213,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
23928 case ZigTypeIdEnumLiteral:23213 case ZigTypeIdEnumLiteral:
23929 case ZigTypeIdUndefined:23214 case ZigTypeIdUndefined:
23930 case ZigTypeIdNull:23215 case ZigTypeIdNull:
23931 case ZigTypeIdPromise:
23932 case ZigTypeIdErrorUnion:23216 case ZigTypeIdErrorUnion:
23933 case ZigTypeIdErrorSet:23217 case ZigTypeIdErrorSet:
23934 zig_unreachable();23218 zig_unreachable();
...@@ -24038,6 +23322,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue...@@ -24038,6 +23322,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
24038 zig_panic("TODO buf_write_value_bytes fn type");23322 zig_panic("TODO buf_write_value_bytes fn type");
24039 case ZigTypeIdUnion:23323 case ZigTypeIdUnion:
24040 zig_panic("TODO buf_write_value_bytes union type");23324 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");
24041 }23329 }
24042 zig_unreachable();23330 zig_unreachable();
24043}23331}
...@@ -24082,7 +23370,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou...@@ -24082,7 +23370,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
24082 case ZigTypeIdEnumLiteral:23370 case ZigTypeIdEnumLiteral:
24083 case ZigTypeIdUndefined:23371 case ZigTypeIdUndefined:
24084 case ZigTypeIdNull:23372 case ZigTypeIdNull:
24085 case ZigTypeIdPromise:
24086 zig_unreachable();23373 zig_unreachable();
24087 case ZigTypeIdVoid:23374 case ZigTypeIdVoid:
24088 return ErrorNone;23375 return ErrorNone;
...@@ -24218,6 +23505,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou...@@ -24218,6 +23505,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
24218 zig_panic("TODO buf_read_value_bytes fn type");23505 zig_panic("TODO buf_read_value_bytes fn type");
24219 case ZigTypeIdUnion:23506 case ZigTypeIdUnion:
24220 zig_panic("TODO buf_read_value_bytes union type");23507 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");
24221 }23512 }
24222 zig_unreachable();23513 zig_unreachable();
24223}23514}
...@@ -24568,184 +23859,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct...@@ -24568,184 +23859,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
24568 }23859 }
24569}23860}
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
24749static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {23862static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
24750 ZigType *operand_type = ir_resolve_type(ira, op);23863 ZigType *operand_type = ir_resolve_type(ira, op);
24751 if (type_is_invalid(operand_type))23864 if (type_is_invalid(operand_type))
...@@ -24877,65 +23990,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr...@@ -24877,65 +23990,6 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr
24877 return result;23990 return result;
24878}23991}
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
24939static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {23993static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
24940 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,23994 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
24941 instruction->base.source_node);23995 instruction->base.source_node);
...@@ -24943,17 +23997,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I...@@ -24943,17 +23997,6 @@ static IrInstruction *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, I
24943 return result;23997 return result;
24944}23998}
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
24957static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,24000static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
24958 ConstExprValue *op, ConstExprValue *out_val) {24001 ConstExprValue *op, ConstExprValue *out_val) {
24959 assert(ira && source_instr && float_type && out_val && op);24002 assert(ira && source_instr && float_type && out_val && op);
...@@ -25480,6 +24523,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i...@@ -25480,6 +24523,162 @@ static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *i
25480 union_type, field_name, field_result_loc, result_loc);24523 union_type, field_name, field_result_loc, result_loc);
25481}24524}
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
25483static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24682static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
25484 switch (instruction->id) {24683 switch (instruction->id) {
25485 case IrInstructionIdInvalid:24684 case IrInstructionIdInvalid:
...@@ -25507,6 +24706,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25507,6 +24706,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25507 case IrInstructionIdSliceGen:24706 case IrInstructionIdSliceGen:
25508 case IrInstructionIdRefGen:24707 case IrInstructionIdRefGen:
25509 case IrInstructionIdTestErrGen:24708 case IrInstructionIdTestErrGen:
24709 case IrInstructionIdFrameSizeGen:
24710 case IrInstructionIdAwaitGen:
25510 zig_unreachable();24711 zig_unreachable();
2551124712
25512 case IrInstructionIdReturn:24713 case IrInstructionIdReturn:
...@@ -25547,6 +24748,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25547,6 +24748,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25547 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);24748 return ir_analyze_instruction_set_runtime_safety(ira, (IrInstructionSetRuntimeSafety *)instruction);
25548 case IrInstructionIdSetFloatMode:24749 case IrInstructionIdSetFloatMode:
25549 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);24750 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);
24751 case IrInstructionIdAnyFrameType:
24752 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
25550 case IrInstructionIdSliceType:24753 case IrInstructionIdSliceType:
25551 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);24754 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
25552 case IrInstructionIdGlobalAsm:24755 case IrInstructionIdGlobalAsm:
...@@ -25555,8 +24758,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25555,8 +24758,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25555 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);24758 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
25556 case IrInstructionIdArrayType:24759 case IrInstructionIdArrayType:
25557 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);24760 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
25558 case IrInstructionIdPromiseType:
25559 return ir_analyze_instruction_promise_type(ira, (IrInstructionPromiseType *)instruction);
25560 case IrInstructionIdSizeOf:24761 case IrInstructionIdSizeOf:
25561 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);24762 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
25562 case IrInstructionIdTestNonNull:24763 case IrInstructionIdTestNonNull:
...@@ -25655,8 +24856,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25655,8 +24856,12 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25655 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);24856 return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
25656 case IrInstructionIdFrameAddress:24857 case IrInstructionIdFrameAddress:
25657 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);24858 return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
25658 case IrInstructionIdHandle:24859 case IrInstructionIdFrameHandle:
25659 return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);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);
25660 case IrInstructionIdAlignOf:24865 case IrInstructionIdAlignOf:
25661 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);24866 return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
25662 case IrInstructionIdOverflowOp:24867 case IrInstructionIdOverflowOp:
...@@ -25711,8 +24916,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25711,8 +24916,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25711 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);24916 return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction);
25712 case IrInstructionIdResetResult:24917 case IrInstructionIdResetResult:
25713 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);24918 return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction);
25714 case IrInstructionIdResultPtr:
25715 return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction);
25716 case IrInstructionIdOpaqueType:24919 case IrInstructionIdOpaqueType:
25717 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);24920 return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
25718 case IrInstructionIdSetAlignStack:24921 case IrInstructionIdSetAlignStack:
...@@ -25727,50 +24930,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25727,50 +24930,14 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25727 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);24930 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
25728 case IrInstructionIdErrorUnion:24931 case IrInstructionIdErrorUnion:
25729 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);24932 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);
25758 case IrInstructionIdAtomicRmw:24933 case IrInstructionIdAtomicRmw:
25759 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);24934 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
25760 case IrInstructionIdAtomicLoad:24935 case IrInstructionIdAtomicLoad:
25761 return ir_analyze_instruction_atomic_load(ira, (IrInstructionAtomicLoad *)instruction);24936 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);
25766 case IrInstructionIdSaveErrRetAddr:24937 case IrInstructionIdSaveErrRetAddr:
25767 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);24938 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
25768 case IrInstructionIdAddImplicitReturnType:24939 case IrInstructionIdAddImplicitReturnType:
25769 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);24940 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);
25774 case IrInstructionIdFloatOp:24941 case IrInstructionIdFloatOp:
25775 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);24942 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
25776 case IrInstructionIdMulAdd:24943 case IrInstructionIdMulAdd:
...@@ -25797,6 +24964,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25797,6 +24964,18 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25797 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);24964 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);
25798 case IrInstructionIdUnionInitNamedField:24965 case IrInstructionIdUnionInitNamedField:
25799 return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction);24966 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);
25800 }24979 }
25801 zig_unreachable();24980 zig_unreachable();
25802}24981}
...@@ -25813,9 +24992,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_...@@ -25813,9 +24992,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
25813 old_exec->analysis = ira;24992 old_exec->analysis = ira;
25814 ira->codegen = codegen;24993 ira->codegen = codegen;
2581524994
25816 ZigFn *fn_entry = exec_fn_entry(old_exec);24995 ira->explicit_return_type = expected_type;
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;
25819 ira->explicit_return_type_source_node = expected_type_source_node;24996 ira->explicit_return_type_source_node = expected_type_source_node;
2582024997
25821 ira->old_irb.codegen = codegen;24998 ira->old_irb.codegen = codegen;
...@@ -25913,19 +25090,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25913,19 +25090,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25913 case IrInstructionIdPtrType:25090 case IrInstructionIdPtrType:
25914 case IrInstructionIdSetAlignStack:25091 case IrInstructionIdSetAlignStack:
25915 case IrInstructionIdExport:25092 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:
25925 case IrInstructionIdSaveErrRetAddr:25093 case IrInstructionIdSaveErrRetAddr:
25926 case IrInstructionIdAddImplicitReturnType:25094 case IrInstructionIdAddImplicitReturnType:
25927 case IrInstructionIdMergeErrRetTraces:
25928 case IrInstructionIdMarkErrRetTracePtr:
25929 case IrInstructionIdAtomicRmw:25095 case IrInstructionIdAtomicRmw:
25930 case IrInstructionIdCmpxchgGen:25096 case IrInstructionIdCmpxchgGen:
25931 case IrInstructionIdCmpxchgSrc:25097 case IrInstructionIdCmpxchgSrc:
...@@ -25940,6 +25106,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25940,6 +25106,12 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25940 case IrInstructionIdOptionalWrap:25106 case IrInstructionIdOptionalWrap:
25941 case IrInstructionIdVectorToArray:25107 case IrInstructionIdVectorToArray:
25942 case IrInstructionIdResetResult:25108 case IrInstructionIdResetResult:
25109 case IrInstructionIdSuspendBegin:
25110 case IrInstructionIdSuspendFinish:
25111 case IrInstructionIdResume:
25112 case IrInstructionIdAwaitSrc:
25113 case IrInstructionIdAwaitGen:
25114 case IrInstructionIdSpillBegin:
25943 return true;25115 return true;
2594425116
25945 case IrInstructionIdPhi:25117 case IrInstructionIdPhi:
...@@ -25958,8 +25130,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25958,8 +25130,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25958 case IrInstructionIdTypeOf:25130 case IrInstructionIdTypeOf:
25959 case IrInstructionIdStructFieldPtr:25131 case IrInstructionIdStructFieldPtr:
25960 case IrInstructionIdArrayType:25132 case IrInstructionIdArrayType:
25961 case IrInstructionIdPromiseType:
25962 case IrInstructionIdSliceType:25133 case IrInstructionIdSliceType:
25134 case IrInstructionIdAnyFrameType:
25963 case IrInstructionIdSizeOf:25135 case IrInstructionIdSizeOf:
25964 case IrInstructionIdTestNonNull:25136 case IrInstructionIdTestNonNull:
25965 case IrInstructionIdOptionalUnwrapPtr:25137 case IrInstructionIdOptionalUnwrapPtr:
...@@ -25985,7 +25157,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25985,7 +25157,10 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25985 case IrInstructionIdAlignOf:25157 case IrInstructionIdAlignOf:
25986 case IrInstructionIdReturnAddress:25158 case IrInstructionIdReturnAddress:
25987 case IrInstructionIdFrameAddress:25159 case IrInstructionIdFrameAddress:
25988 case IrInstructionIdHandle:25160 case IrInstructionIdFrameHandle:
25161 case IrInstructionIdFrameType:
25162 case IrInstructionIdFrameSizeSrc:
25163 case IrInstructionIdFrameSizeGen:
25989 case IrInstructionIdTestErrSrc:25164 case IrInstructionIdTestErrSrc:
25990 case IrInstructionIdTestErrGen:25165 case IrInstructionIdTestErrGen:
25991 case IrInstructionIdFnProto:25166 case IrInstructionIdFnProto:
...@@ -26018,13 +25193,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -26018,13 +25193,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
26018 case IrInstructionIdTagType:25193 case IrInstructionIdTagType:
26019 case IrInstructionIdErrorReturnTrace:25194 case IrInstructionIdErrorReturnTrace:
26020 case IrInstructionIdErrorUnion:25195 case IrInstructionIdErrorUnion:
26021 case IrInstructionIdGetImplicitAllocator:
26022 case IrInstructionIdCoroAlloc:
26023 case IrInstructionIdCoroSize:
26024 case IrInstructionIdCoroSuspend:
26025 case IrInstructionIdCoroFree:
26026 case IrInstructionIdCoroPromise:
26027 case IrInstructionIdPromiseResultType:
26028 case IrInstructionIdFloatOp:25196 case IrInstructionIdFloatOp:
26029 case IrInstructionIdMulAdd:25197 case IrInstructionIdMulAdd:
26030 case IrInstructionIdAtomicLoad:25198 case IrInstructionIdAtomicLoad:
...@@ -26041,7 +25209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -26041,7 +25209,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
26041 case IrInstructionIdHasDecl:25209 case IrInstructionIdHasDecl:
26042 case IrInstructionIdAllocaSrc:25210 case IrInstructionIdAllocaSrc:
26043 case IrInstructionIdAllocaGen:25211 case IrInstructionIdAllocaGen:
26044 case IrInstructionIdResultPtr:25212 case IrInstructionIdSpillEnd:
26045 return false;25213 return false;
2604625214
26047 case IrInstructionIdAsm:25215 case IrInstructionIdAsm:
src/ir.hpp+2
...@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal...@@ -28,4 +28,6 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
28 AstNode *source_node);28 AstNode *source_node);
29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
3030
31void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text);
32
31#endif33#endif
src/ir_print.cpp+109-224
...@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {...@@ -64,11 +64,9 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
64 }64 }
65}65}
6666
67static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {67static void ir_print_return(IrPrint *irp, IrInstructionReturn *instruction) {
68 fprintf(irp->f, "return ");68 fprintf(irp->f, "return ");
69 if (return_instruction->value != nullptr) {69 ir_print_other_instruction(irp, instruction->operand);
70 ir_print_other_instruction(irp, return_instruction->value);
71 }
72}70}
7371
74static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {72static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
...@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {...@@ -257,13 +255,7 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
257255
258static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {256static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {
259 if (call_instruction->is_async) {257 if (call_instruction->is_async) {
260 fprintf(irp->f, "async");258 fprintf(irp->f, "async ");
261 if (call_instruction->async_allocator != nullptr) {
262 fprintf(irp->f, "<");
263 ir_print_other_instruction(irp, call_instruction->async_allocator);
264 fprintf(irp->f, ">");
265 }
266 fprintf(irp->f, " ");
267 }259 }
268 if (call_instruction->fn_entry) {260 if (call_instruction->fn_entry) {
269 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));261 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
...@@ -284,13 +276,7 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi...@@ -284,13 +276,7 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi
284276
285static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {277static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {
286 if (call_instruction->is_async) {278 if (call_instruction->is_async) {
287 fprintf(irp->f, "async");279 fprintf(irp->f, "async ");
288 if (call_instruction->async_allocator != nullptr) {
289 fprintf(irp->f, "<");
290 ir_print_other_instruction(irp, call_instruction->async_allocator);
291 fprintf(irp->f, ">");
292 }
293 fprintf(irp->f, " ");
294 }280 }
295 if (call_instruction->fn_entry) {281 if (call_instruction->fn_entry) {
296 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));282 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
...@@ -477,20 +463,21 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio...@@ -477,20 +463,21 @@ static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instructio
477 ir_print_other_instruction(irp, instruction->child_type);463 ir_print_other_instruction(irp, instruction->child_type);
478}464}
479465
480static void ir_print_promise_type(IrPrint *irp, IrInstructionPromiseType *instruction) {
481 fprintf(irp->f, "promise");
482 if (instruction->payload_type != nullptr) {
483 fprintf(irp->f, "->");
484 ir_print_other_instruction(irp, instruction->payload_type);
485 }
486}
487
488static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {466static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instruction) {
489 const char *const_kw = instruction->is_const ? "const " : "";467 const char *const_kw = instruction->is_const ? "const " : "";
490 fprintf(irp->f, "[]%s", const_kw);468 fprintf(irp->f, "[]%s", const_kw);
491 ir_print_other_instruction(irp, instruction->child_type);469 ir_print_other_instruction(irp, instruction->child_type);
492}470}
493471
472static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *instruction) {
473 if (instruction->payload_type == nullptr) {
474 fprintf(irp->f, "anyframe");
475 } else {
476 fprintf(irp->f, "anyframe->");
477 ir_print_other_instruction(irp, instruction->payload_type);
478 }
479}
480
494static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {481static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {
495 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));482 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));
496}483}
...@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst...@@ -926,8 +913,26 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
926 fprintf(irp->f, "@frameAddress()");913 fprintf(irp->f, "@frameAddress()");
927}914}
928915
929static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {916static void ir_print_handle(IrPrint *irp, IrInstructionFrameHandle *instruction) {
930 fprintf(irp->f, "@handle()");917 fprintf(irp->f, "@frame()");
918}
919
920static void ir_print_frame_type(IrPrint *irp, IrInstructionFrameType *instruction) {
921 fprintf(irp->f, "@Frame(");
922 ir_print_other_instruction(irp, instruction->fn);
923 fprintf(irp->f, ")");
924}
925
926static void ir_print_frame_size_src(IrPrint *irp, IrInstructionFrameSizeSrc *instruction) {
927 fprintf(irp->f, "@frameSize(");
928 ir_print_other_instruction(irp, instruction->fn);
929 fprintf(irp->f, ")");
930}
931
932static void ir_print_frame_size_gen(IrPrint *irp, IrInstructionFrameSizeGen *instruction) {
933 fprintf(irp->f, "@frameSize(");
934 ir_print_other_instruction(irp, instruction->fn);
935 fprintf(irp->f, ")");
931}936}
932937
933static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {938static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
...@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru...@@ -1322,14 +1327,6 @@ static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instru
1322 fprintf(irp->f, ")");1327 fprintf(irp->f, ")");
1323}1328}
13241329
1325static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) {
1326 fprintf(irp->f, "ResultPtr(");
1327 ir_print_result_loc(irp, instruction->result_loc);
1328 fprintf(irp->f, ",");
1329 ir_print_other_instruction(irp, instruction->result);
1330 fprintf(irp->f, ")");
1331}
1332
1333static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {1330static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
1334 fprintf(irp->f, "@OpaqueType()");1331 fprintf(irp->f, "@OpaqueType()");
1335}1332}
...@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct...@@ -1391,110 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
1391 ir_print_other_instruction(irp, instruction->payload);1388 ir_print_other_instruction(irp, instruction->payload);
1392}1389}
13931390
1394static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
1395 fprintf(irp->f, "cancel ");
1396 ir_print_other_instruction(irp, instruction->target);
1397}
1398
1399static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplicitAllocator *instruction) {
1400 fprintf(irp->f, "@getImplicitAllocator(");
1401 switch (instruction->id) {
1402 case ImplicitAllocatorIdArg:
1403 fprintf(irp->f, "Arg");
1404 break;
1405 case ImplicitAllocatorIdLocalVar:
1406 fprintf(irp->f, "LocalVar");
1407 break;
1408 }
1409 fprintf(irp->f, ")");
1410}
1411
1412static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1413 fprintf(irp->f, "@coroId(");
1414 ir_print_other_instruction(irp, instruction->promise_ptr);
1415 fprintf(irp->f, ")");
1416}
1417
1418static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
1419 fprintf(irp->f, "@coroAlloc(");
1420 ir_print_other_instruction(irp, instruction->coro_id);
1421 fprintf(irp->f, ")");
1422}
1423
1424static void ir_print_coro_size(IrPrint *irp, IrInstructionCoroSize *instruction) {
1425 fprintf(irp->f, "@coroSize()");
1426}
1427
1428static void ir_print_coro_begin(IrPrint *irp, IrInstructionCoroBegin *instruction) {
1429 fprintf(irp->f, "@coroBegin(");
1430 ir_print_other_instruction(irp, instruction->coro_id);
1431 fprintf(irp->f, ",");
1432 ir_print_other_instruction(irp, instruction->coro_mem_ptr);
1433 fprintf(irp->f, ")");
1434}
1435
1436static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *instruction) {
1437 fprintf(irp->f, "@coroAllocFail(");
1438 ir_print_other_instruction(irp, instruction->err_val);
1439 fprintf(irp->f, ")");
1440}
1441
1442static void ir_print_coro_suspend(IrPrint *irp, IrInstructionCoroSuspend *instruction) {
1443 fprintf(irp->f, "@coroSuspend(");
1444 if (instruction->save_point != nullptr) {
1445 ir_print_other_instruction(irp, instruction->save_point);
1446 } else {
1447 fprintf(irp->f, "null");
1448 }
1449 fprintf(irp->f, ",");
1450 ir_print_other_instruction(irp, instruction->is_final);
1451 fprintf(irp->f, ")");
1452}
1453
1454static void ir_print_coro_end(IrPrint *irp, IrInstructionCoroEnd *instruction) {
1455 fprintf(irp->f, "@coroEnd()");
1456}
1457
1458static void ir_print_coro_free(IrPrint *irp, IrInstructionCoroFree *instruction) {
1459 fprintf(irp->f, "@coroFree(");
1460 ir_print_other_instruction(irp, instruction->coro_id);
1461 fprintf(irp->f, ",");
1462 ir_print_other_instruction(irp, instruction->coro_handle);
1463 fprintf(irp->f, ")");
1464}
1465
1466static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) {
1467 fprintf(irp->f, "@coroResume(");
1468 ir_print_other_instruction(irp, instruction->awaiter_handle);
1469 fprintf(irp->f, ")");
1470}
1471
1472static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction) {
1473 fprintf(irp->f, "@coroSave(");
1474 ir_print_other_instruction(irp, instruction->coro_handle);
1475 fprintf(irp->f, ")");
1476}
1477
1478static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1479 fprintf(irp->f, "@coroPromise(");
1480 ir_print_other_instruction(irp, instruction->coro_handle);
1481 fprintf(irp->f, ")");
1482}
1483
1484static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1485 fprintf(irp->f, "@PromiseResultType(");
1486 ir_print_other_instruction(irp, instruction->promise_type);
1487 fprintf(irp->f, ")");
1488}
1489
1490static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
1491 fprintf(irp->f, "@coroAllocHelper(");
1492 ir_print_other_instruction(irp, instruction->realloc_fn);
1493 fprintf(irp->f, ",");
1494 ir_print_other_instruction(irp, instruction->coro_size);
1495 fprintf(irp->f, ")");
1496}
1497
1498static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {1391static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
1499 fprintf(irp->f, "@atomicRmw(");1392 fprintf(irp->f, "@atomicRmw(");
1500 if (instruction->operand_type != nullptr) {1393 if (instruction->operand_type != nullptr) {
...@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct...@@ -1539,12 +1432,6 @@ static void ir_print_atomic_load(IrPrint *irp, IrInstructionAtomicLoad *instruct
1539 fprintf(irp->f, ")");1432 fprintf(irp->f, ")");
1540}1433}
15411434
1542static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
1543 fprintf(irp->f, "@awaitBookkeeping(");
1544 ir_print_other_instruction(irp, instruction->promise_result_type);
1545 fprintf(irp->f, ")");
1546}
1547
1548static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {1435static void ir_print_save_err_ret_addr(IrPrint *irp, IrInstructionSaveErrRetAddr *instruction) {
1549 fprintf(irp->f, "@saveErrRetAddr()");1436 fprintf(irp->f, "@saveErrRetAddr()");
1550}1437}
...@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl...@@ -1555,22 +1442,6 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
1555 fprintf(irp->f, ")");1442 fprintf(irp->f, ")");
1556}1443}
15571444
1558static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1559 fprintf(irp->f, "@mergeErrRetTraces(");
1560 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1561 fprintf(irp->f, ",");
1562 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1563 fprintf(irp->f, ",");
1564 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1565 fprintf(irp->f, ")");
1566}
1567
1568static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1569 fprintf(irp->f, "@markErrRetTracePtr(");
1570 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1571 fprintf(irp->f, ")");
1572}
1573
1574static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {1445static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
15751446
1576 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));1447 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
...@@ -1638,6 +1509,47 @@ static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInit...@@ -1638,6 +1509,47 @@ static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInit
1638 fprintf(irp->f, ")");1509 fprintf(irp->f, ")");
1639}1510}
16401511
1512static void ir_print_suspend_begin(IrPrint *irp, IrInstructionSuspendBegin *instruction) {
1513 fprintf(irp->f, "@suspendBegin()");
1514}
1515
1516static void ir_print_suspend_finish(IrPrint *irp, IrInstructionSuspendFinish *instruction) {
1517 fprintf(irp->f, "@suspendFinish()");
1518}
1519
1520static void ir_print_resume(IrPrint *irp, IrInstructionResume *instruction) {
1521 fprintf(irp->f, "resume ");
1522 ir_print_other_instruction(irp, instruction->frame);
1523}
1524
1525static void ir_print_await_src(IrPrint *irp, IrInstructionAwaitSrc *instruction) {
1526 fprintf(irp->f, "@await(");
1527 ir_print_other_instruction(irp, instruction->frame);
1528 fprintf(irp->f, ",");
1529 ir_print_result_loc(irp, instruction->result_loc);
1530 fprintf(irp->f, ")");
1531}
1532
1533static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction) {
1534 fprintf(irp->f, "@await(");
1535 ir_print_other_instruction(irp, instruction->frame);
1536 fprintf(irp->f, ",");
1537 ir_print_other_instruction(irp, instruction->result_loc);
1538 fprintf(irp->f, ")");
1539}
1540
1541static void ir_print_spill_begin(IrPrint *irp, IrInstructionSpillBegin *instruction) {
1542 fprintf(irp->f, "@spillBegin(");
1543 ir_print_other_instruction(irp, instruction->operand);
1544 fprintf(irp->f, ")");
1545}
1546
1547static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) {
1548 fprintf(irp->f, "@spillEnd(");
1549 ir_print_other_instruction(irp, &instruction->begin->base);
1550 fprintf(irp->f, ")");
1551}
1552
1641static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1553static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1642 ir_print_prefix(irp, instruction);1554 ir_print_prefix(irp, instruction);
1643 switch (instruction->id) {1555 switch (instruction->id) {
...@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1727,12 +1639,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1727 case IrInstructionIdArrayType:1639 case IrInstructionIdArrayType:
1728 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);1640 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
1729 break;1641 break;
1730 case IrInstructionIdPromiseType:
1731 ir_print_promise_type(irp, (IrInstructionPromiseType *)instruction);
1732 break;
1733 case IrInstructionIdSliceType:1642 case IrInstructionIdSliceType:
1734 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);1643 ir_print_slice_type(irp, (IrInstructionSliceType *)instruction);
1735 break;1644 break;
1645 case IrInstructionIdAnyFrameType:
1646 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
1647 break;
1736 case IrInstructionIdGlobalAsm:1648 case IrInstructionIdGlobalAsm:
1737 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);1649 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);
1738 break;1650 break;
...@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1886,8 +1798,17 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1886 case IrInstructionIdFrameAddress:1798 case IrInstructionIdFrameAddress:
1887 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);1799 ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
1888 break;1800 break;
1889 case IrInstructionIdHandle:1801 case IrInstructionIdFrameHandle:
1890 ir_print_handle(irp, (IrInstructionHandle *)instruction);1802 ir_print_handle(irp, (IrInstructionFrameHandle *)instruction);
1803 break;
1804 case IrInstructionIdFrameType:
1805 ir_print_frame_type(irp, (IrInstructionFrameType *)instruction);
1806 break;
1807 case IrInstructionIdFrameSizeSrc:
1808 ir_print_frame_size_src(irp, (IrInstructionFrameSizeSrc *)instruction);
1809 break;
1810 case IrInstructionIdFrameSizeGen:
1811 ir_print_frame_size_gen(irp, (IrInstructionFrameSizeGen *)instruction);
1891 break;1812 break;
1892 case IrInstructionIdAlignOf:1813 case IrInstructionIdAlignOf:
1893 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);1814 ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
...@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2006,9 +1927,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2006 case IrInstructionIdResetResult:1927 case IrInstructionIdResetResult:
2007 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);1928 ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);
2008 break;1929 break;
2009 case IrInstructionIdResultPtr:
2010 ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
2011 break;
2012 case IrInstructionIdOpaqueType:1930 case IrInstructionIdOpaqueType:
2013 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);1931 ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
2014 break;1932 break;
...@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2030,69 +1948,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2030 case IrInstructionIdErrorUnion:1948 case IrInstructionIdErrorUnion:
2031 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);1949 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
2032 break;1950 break;
2033 case IrInstructionIdCancel:
2034 ir_print_cancel(irp, (IrInstructionCancel *)instruction);
2035 break;
2036 case IrInstructionIdGetImplicitAllocator:
2037 ir_print_get_implicit_allocator(irp, (IrInstructionGetImplicitAllocator *)instruction);
2038 break;
2039 case IrInstructionIdCoroId:
2040 ir_print_coro_id(irp, (IrInstructionCoroId *)instruction);
2041 break;
2042 case IrInstructionIdCoroAlloc:
2043 ir_print_coro_alloc(irp, (IrInstructionCoroAlloc *)instruction);
2044 break;
2045 case IrInstructionIdCoroSize:
2046 ir_print_coro_size(irp, (IrInstructionCoroSize *)instruction);
2047 break;
2048 case IrInstructionIdCoroBegin:
2049 ir_print_coro_begin(irp, (IrInstructionCoroBegin *)instruction);
2050 break;
2051 case IrInstructionIdCoroAllocFail:
2052 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);
2053 break;
2054 case IrInstructionIdCoroSuspend:
2055 ir_print_coro_suspend(irp, (IrInstructionCoroSuspend *)instruction);
2056 break;
2057 case IrInstructionIdCoroEnd:
2058 ir_print_coro_end(irp, (IrInstructionCoroEnd *)instruction);
2059 break;
2060 case IrInstructionIdCoroFree:
2061 ir_print_coro_free(irp, (IrInstructionCoroFree *)instruction);
2062 break;
2063 case IrInstructionIdCoroResume:
2064 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
2065 break;
2066 case IrInstructionIdCoroSave:
2067 ir_print_coro_save(irp, (IrInstructionCoroSave *)instruction);
2068 break;
2069 case IrInstructionIdCoroAllocHelper:
2070 ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction);
2071 break;
2072 case IrInstructionIdAtomicRmw:1951 case IrInstructionIdAtomicRmw:
2073 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);1952 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
2074 break;1953 break;
2075 case IrInstructionIdCoroPromise:
2076 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
2077 break;
2078 case IrInstructionIdPromiseResultType:
2079 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
2080 break;
2081 case IrInstructionIdAwaitBookkeeping:
2082 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
2083 break;
2084 case IrInstructionIdSaveErrRetAddr:1954 case IrInstructionIdSaveErrRetAddr:
2085 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);1955 ir_print_save_err_ret_addr(irp, (IrInstructionSaveErrRetAddr *)instruction);
2086 break;1956 break;
2087 case IrInstructionIdAddImplicitReturnType:1957 case IrInstructionIdAddImplicitReturnType:
2088 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);1958 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
2089 break;1959 break;
2090 case IrInstructionIdMergeErrRetTraces:
2091 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
2092 break;
2093 case IrInstructionIdMarkErrRetTracePtr:
2094 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
2095 break;
2096 case IrInstructionIdFloatOp:1960 case IrInstructionIdFloatOp:
2097 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);1961 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
2098 break;1962 break;
...@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2147,6 +2011,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2147 case IrInstructionIdUnionInitNamedField:2011 case IrInstructionIdUnionInitNamedField:
2148 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);2012 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);
2149 break;2013 break;
2014 case IrInstructionIdSuspendBegin:
2015 ir_print_suspend_begin(irp, (IrInstructionSuspendBegin *)instruction);
2016 break;
2017 case IrInstructionIdSuspendFinish:
2018 ir_print_suspend_finish(irp, (IrInstructionSuspendFinish *)instruction);
2019 break;
2020 case IrInstructionIdResume:
2021 ir_print_resume(irp, (IrInstructionResume *)instruction);
2022 break;
2023 case IrInstructionIdAwaitSrc:
2024 ir_print_await_src(irp, (IrInstructionAwaitSrc *)instruction);
2025 break;
2026 case IrInstructionIdAwaitGen:
2027 ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction);
2028 break;
2029 case IrInstructionIdSpillBegin:
2030 ir_print_spill_begin(irp, (IrInstructionSpillBegin *)instruction);
2031 break;
2032 case IrInstructionIdSpillEnd:
2033 ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction);
2034 break;
2150 }2035 }
2151 fprintf(irp->f, "\n");2036 fprintf(irp->f, "\n");
2152}2037}
src/main.cpp+1-1
...@@ -85,7 +85,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -85,7 +85,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
85 " --verbose-cc enable compiler debug output for C compilation\n"85 " --verbose-cc enable compiler debug output for C compilation\n"
86 " -dirafter [dir] same as -isystem but do it last\n"86 " -dirafter [dir] same as -isystem but do it last\n"
87 " -isystem [dir] add additional search path for other .h files\n"87 " -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"
89 " --override-std-dir [arg] override path to Zig standard library\n"89 " --override-std-dir [arg] override path to Zig standard library\n"
90 " --override-lib-dir [arg] override path to Zig lib library\n"90 " --override-lib-dir [arg] override path to Zig lib library\n"
91 " -ffunction-sections places each function in a seperate section\n"91 " -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);...@@ -113,7 +113,6 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc);
113static AstNode *ast_parse_prefix_op(ParseContext *pc);113static AstNode *ast_parse_prefix_op(ParseContext *pc);
114static AstNode *ast_parse_prefix_type_op(ParseContext *pc);114static AstNode *ast_parse_prefix_type_op(ParseContext *pc);
115static AstNode *ast_parse_suffix_op(ParseContext *pc);115static AstNode *ast_parse_suffix_op(ParseContext *pc);
116static AstNode *ast_parse_async_prefix(ParseContext *pc);
117static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc);116static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc);
118static AstNode *ast_parse_array_type_start(ParseContext *pc);117static AstNode *ast_parse_array_type_start(ParseContext *pc);
119static AstNode *ast_parse_ptr_type_start(ParseContext *pc);118static AstNode *ast_parse_ptr_type_start(ParseContext *pc);
...@@ -282,8 +281,8 @@ static AstNode *ast_parse_prefix_op_expr(...@@ -282,8 +281,8 @@ static AstNode *ast_parse_prefix_op_expr(
282 case NodeTypeAwaitExpr:281 case NodeTypeAwaitExpr:
283 right = &prefix->data.await_expr.expr;282 right = &prefix->data.await_expr.expr;
284 break;283 break;
285 case NodeTypePromiseType:284 case NodeTypeAnyFrameType:
286 right = &prefix->data.promise_type.payload_type;285 right = &prefix->data.anyframe_type.payload_type;
287 break;286 break;
288 case NodeTypeArrayType:287 case NodeTypeArrayType:
289 right = &prefix->data.array_type.child_type;288 right = &prefix->data.array_type.child_type;
...@@ -1167,7 +1166,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {...@@ -1167,7 +1166,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
1167// <- AsmExpr1166// <- AsmExpr
1168// / IfExpr1167// / IfExpr
1169// / KEYWORD_break BreakLabel? Expr?1168// / KEYWORD_break BreakLabel? Expr?
1170// / KEYWORD_cancel Expr
1171// / KEYWORD_comptime Expr1169// / KEYWORD_comptime Expr
1172// / KEYWORD_continue BreakLabel?1170// / KEYWORD_continue BreakLabel?
1173// / KEYWORD_resume Expr1171// / KEYWORD_resume Expr
...@@ -1195,14 +1193,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {...@@ -1195,14 +1193,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
1195 return res;1193 return res;
1196 }1194 }
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
1206 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);1196 Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime);
1207 if (comptime != nullptr) {1197 if (comptime != nullptr) {
1208 AstNode *expr = ast_expect(pc, ast_parse_expr);1198 AstNode *expr = ast_expect(pc, ast_parse_expr);
...@@ -1398,22 +1388,18 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {...@@ -1398,22 +1388,18 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
1398}1388}
13991389
1400// SuffixExpr1390// SuffixExpr
1401// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments1391// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
1402// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*1392// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1403static AstNode *ast_parse_suffix_expr(ParseContext *pc) {1393static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
1404 AstNode *async_call = ast_parse_async_prefix(pc);1394 Token *async_token = eat_token_if(pc, TokenIdKeywordAsync);
1405 if (async_call != nullptr) {1395 if (async_token != nullptr) {
1406 if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {1396 if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
1407 // HACK: If we see the keyword `fn`, then we assume that1397 // HACK: If we see the keyword `fn`, then we assume that
1408 // we are parsing an async fn proto, and not a call.1398 // we are parsing an async fn proto, and not a call.
1409 // We therefore put back all tokens consumed by the async1399 // We therefore put back all tokens consumed by the async
1410 // prefix...1400 // prefix...
1411 // HACK: This loop is not actually enough to put back all the1401 put_back_token(pc);
1412 // tokens. Let's hope this is fine for most code right now1402 put_back_token(pc);
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);
14171403
1418 return ast_parse_primary_type_expr(pc);1404 return ast_parse_primary_type_expr(pc);
1419 }1405 }
...@@ -1455,10 +1441,14 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {...@@ -1455,10 +1441,14 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
1455 ast_invalid_token_error(pc, peek_token(pc));1441 ast_invalid_token_error(pc, peek_token(pc));
14561442
1457 assert(args->type == NodeTypeFnCallExpr);1443 assert(args->type == NodeTypeFnCallExpr);
1458 async_call->data.fn_call_expr.fn_ref_expr = child;1444
1459 async_call->data.fn_call_expr.params = args->data.fn_call_expr.params;1445 AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token);
1460 async_call->data.fn_call_expr.is_builtin = false;1446 res->data.fn_call_expr.is_async = true;
1461 return async_call;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;
1462 }1452 }
14631453
1464 AstNode *res = ast_parse_primary_type_expr(pc);1454 AstNode *res = ast_parse_primary_type_expr(pc);
...@@ -1510,7 +1500,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {...@@ -1510,7 +1500,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
1510// <- BUILTINIDENTIFIER FnCallArguments1500// <- BUILTINIDENTIFIER FnCallArguments
1511// / CHAR_LITERAL1501// / CHAR_LITERAL
1512// / ContainerDecl1502// / ContainerDecl
1513// / DOT IDENTIFIER1503// / DOT IDENTIFIER
1514// / ErrorSetDecl1504// / ErrorSetDecl
1515// / FLOAT1505// / FLOAT
1516// / FnProto1506// / FnProto
...@@ -1643,9 +1633,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {...@@ -1643,9 +1633,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
1643 if (null != nullptr)1633 if (null != nullptr)
1644 return ast_create_node(pc, NodeTypeNullLiteral, null);1634 return ast_create_node(pc, NodeTypeNullLiteral, null);
16451635
1646 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);1636 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
1647 if (promise != nullptr)1637 if (anyframe != nullptr)
1648 return ast_create_node(pc, NodeTypePromiseType, promise);1638 return ast_create_node(pc, NodeTypeAnyFrameType, anyframe);
16491639
1650 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);1640 Token *true_token = eat_token_if(pc, TokenIdKeywordTrue);
1651 if (true_token != nullptr) {1641 if (true_token != nullptr) {
...@@ -2025,7 +2015,7 @@ static AstNode *ast_parse_link_section(ParseContext *pc) {...@@ -2025,7 +2015,7 @@ static AstNode *ast_parse_link_section(ParseContext *pc) {
2025// <- KEYWORD_nakedcc2015// <- KEYWORD_nakedcc
2026// / KEYWORD_stdcallcc2016// / KEYWORD_stdcallcc
2027// / KEYWORD_extern2017// / KEYWORD_extern
2028// / KEYWORD_async (LARROW TypeExpr RARROW)?2018// / KEYWORD_async
2029static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {2019static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
2030 AstNodeFnProto res = {};2020 AstNodeFnProto res = {};
2031 if (eat_token_if(pc, TokenIdKeywordNakedCC) != nullptr) {2021 if (eat_token_if(pc, TokenIdKeywordNakedCC) != nullptr) {
...@@ -2042,11 +2032,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {...@@ -2042,11 +2032,6 @@ static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc) {
2042 }2032 }
2043 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {2033 if (eat_token_if(pc, TokenIdKeywordAsync) != nullptr) {
2044 res.cc = CallingConventionAsync;2034 res.cc = CallingConventionAsync;
2045 if (eat_token_if(pc, TokenIdCmpLessThan) == nullptr)
2046 return Optional<AstNodeFnProto>::some(res);
2047
2048 res.async_allocator_type = ast_expect(pc, ast_parse_type_expr);
2049 expect_token(pc, TokenIdCmpGreaterThan);
2050 return Optional<AstNodeFnProto>::some(res);2035 return Optional<AstNodeFnProto>::some(res);
2051 }2036 }
20522037
...@@ -2522,7 +2507,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {...@@ -2522,7 +2507,7 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
25222507
2523// PrefixTypeOp2508// PrefixTypeOp
2524// <- QUESTIONMARK2509// <- QUESTIONMARK
2525// / KEYWORD_promise MINUSRARROW2510// / KEYWORD_anyframe MINUSRARROW
2526// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*2511// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
2527// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*2512// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
2528static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {2513static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
...@@ -2533,10 +2518,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {...@@ -2533,10 +2518,10 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
2533 return res;2518 return res;
2534 }2519 }
25352520
2536 Token *promise = eat_token_if(pc, TokenIdKeywordPromise);2521 Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame);
2537 if (promise != nullptr) {2522 if (anyframe != nullptr) {
2538 if (eat_token_if(pc, TokenIdArrow) != nullptr) {2523 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);
2540 return res;2525 return res;
2541 }2526 }
25422527
...@@ -2671,24 +2656,6 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) {...@@ -2671,24 +2656,6 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) {
2671 return nullptr;2656 return nullptr;
2672}2657}
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
2692// FnCallArguments <- LPAREN ExprList RPAREN2659// FnCallArguments <- LPAREN ExprList RPAREN
2693static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {2660static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {
2694 Token *paren = eat_token_if(pc, TokenIdLParen);2661 Token *paren = eat_token_if(pc, TokenIdLParen);
...@@ -2858,7 +2825,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2858,7 +2825,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2858 visit_node_list(&node->data.fn_proto.params, visit, context);2825 visit_node_list(&node->data.fn_proto.params, visit, context);
2859 visit_field(&node->data.fn_proto.align_expr, visit, context);2826 visit_field(&node->data.fn_proto.align_expr, visit, context);
2860 visit_field(&node->data.fn_proto.section_expr, visit, context);2827 visit_field(&node->data.fn_proto.section_expr, visit, context);
2861 visit_field(&node->data.fn_proto.async_allocator_type, visit, context);
2862 break;2828 break;
2863 case NodeTypeFnDef:2829 case NodeTypeFnDef:
2864 visit_field(&node->data.fn_def.fn_proto, visit, context);2830 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...@@ -2918,7 +2884,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2918 case NodeTypeFnCallExpr:2884 case NodeTypeFnCallExpr:
2919 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);2885 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
2920 visit_node_list(&node->data.fn_call_expr.params, visit, context);2886 visit_node_list(&node->data.fn_call_expr.params, visit, context);
2921 visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
2922 break;2887 break;
2923 case NodeTypeArrayAccessExpr:2888 case NodeTypeArrayAccessExpr:
2924 visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);2889 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...@@ -3034,8 +2999,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3034 case NodeTypeInferredArrayType:2999 case NodeTypeInferredArrayType:
3035 visit_field(&node->data.array_type.child_type, visit, context);3000 visit_field(&node->data.array_type.child_type, visit, context);
3036 break;3001 break;
3037 case NodeTypePromiseType:3002 case NodeTypeAnyFrameType:
3038 visit_field(&node->data.promise_type.payload_type, visit, context);3003 visit_field(&node->data.anyframe_type.payload_type, visit, context);
3039 break;3004 break;
3040 case NodeTypeErrorType:3005 case NodeTypeErrorType:
3041 // none3006 // none
...@@ -3047,9 +3012,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -3047,9 +3012,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
3047 case NodeTypeErrorSetDecl:3012 case NodeTypeErrorSetDecl:
3048 visit_node_list(&node->data.err_set_decl.decls, visit, context);3013 visit_node_list(&node->data.err_set_decl.decls, visit, context);
3049 break;3014 break;
3050 case NodeTypeCancel:
3051 visit_field(&node->data.cancel_expr.expr, visit, context);
3052 break;
3053 case NodeTypeResume:3015 case NodeTypeResume:
3054 visit_field(&node->data.resume_expr.expr, visit, context);3016 visit_field(&node->data.resume_expr.expr, visit, context);
3055 break;3017 break;
src/target.cpp+61-1
...@@ -665,7 +665,63 @@ ZigLLVM_SubArchType target_subarch_enum(SubArchList sub_arch_list, size_t i) {...@@ -665,7 +665,63 @@ ZigLLVM_SubArchType target_subarch_enum(SubArchList sub_arch_list, size_t i) {
665}665}
666666
667const char *target_subarch_name(ZigLLVM_SubArchType subarch) {667const 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();
669}725}
670726
671size_t target_subarch_list_count(void) {727size_t target_subarch_list_count(void) {
...@@ -1827,3 +1883,7 @@ bool target_libc_needs_crti_crtn(const ZigTarget *target) {...@@ -1827,3 +1883,7 @@ bool target_libc_needs_crti_crtn(const ZigTarget *target) {
1827bool target_is_riscv(const ZigTarget *target) {1883bool target_is_riscv(const ZigTarget *target) {
1828 return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64;1884 return target->arch == ZigLLVM_riscv32 || target->arch == ZigLLVM_riscv64;
1829}1885}
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);...@@ -201,4 +201,6 @@ size_t target_libc_count(void);
201void target_libc_enum(size_t index, ZigTarget *out_target);201void target_libc_enum(size_t index, ZigTarget *out_target);
202bool target_libc_needs_crti_crtn(const ZigTarget *target);202bool target_libc_needs_crti_crtn(const ZigTarget *target);
203203
204unsigned target_fn_align(const ZigTarget *target);
205
204#endif206#endif
src/tokenizer.cpp+2-4
...@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -109,11 +109,11 @@ static const struct ZigKeyword zig_keywords[] = {
109 {"align", TokenIdKeywordAlign},109 {"align", TokenIdKeywordAlign},
110 {"allowzero", TokenIdKeywordAllowZero},110 {"allowzero", TokenIdKeywordAllowZero},
111 {"and", TokenIdKeywordAnd},111 {"and", TokenIdKeywordAnd},
112 {"anyframe", TokenIdKeywordAnyFrame},
112 {"asm", TokenIdKeywordAsm},113 {"asm", TokenIdKeywordAsm},
113 {"async", TokenIdKeywordAsync},114 {"async", TokenIdKeywordAsync},
114 {"await", TokenIdKeywordAwait},115 {"await", TokenIdKeywordAwait},
115 {"break", TokenIdKeywordBreak},116 {"break", TokenIdKeywordBreak},
116 {"cancel", TokenIdKeywordCancel},
117 {"catch", TokenIdKeywordCatch},117 {"catch", TokenIdKeywordCatch},
118 {"comptime", TokenIdKeywordCompTime},118 {"comptime", TokenIdKeywordCompTime},
119 {"const", TokenIdKeywordConst},119 {"const", TokenIdKeywordConst},
...@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -136,7 +136,6 @@ static const struct ZigKeyword zig_keywords[] = {
136 {"or", TokenIdKeywordOr},136 {"or", TokenIdKeywordOr},
137 {"orelse", TokenIdKeywordOrElse},137 {"orelse", TokenIdKeywordOrElse},
138 {"packed", TokenIdKeywordPacked},138 {"packed", TokenIdKeywordPacked},
139 {"promise", TokenIdKeywordPromise},
140 {"pub", TokenIdKeywordPub},139 {"pub", TokenIdKeywordPub},
141 {"resume", TokenIdKeywordResume},140 {"resume", TokenIdKeywordResume},
142 {"return", TokenIdKeywordReturn},141 {"return", TokenIdKeywordReturn},
...@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {...@@ -1531,9 +1530,9 @@ const char * token_name(TokenId id) {
1531 case TokenIdKeywordAwait: return "await";1530 case TokenIdKeywordAwait: return "await";
1532 case TokenIdKeywordResume: return "resume";1531 case TokenIdKeywordResume: return "resume";
1533 case TokenIdKeywordSuspend: return "suspend";1532 case TokenIdKeywordSuspend: return "suspend";
1534 case TokenIdKeywordCancel: return "cancel";
1535 case TokenIdKeywordAlign: return "align";1533 case TokenIdKeywordAlign: return "align";
1536 case TokenIdKeywordAnd: return "and";1534 case TokenIdKeywordAnd: return "and";
1535 case TokenIdKeywordAnyFrame: return "anyframe";
1537 case TokenIdKeywordAsm: return "asm";1536 case TokenIdKeywordAsm: return "asm";
1538 case TokenIdKeywordBreak: return "break";1537 case TokenIdKeywordBreak: return "break";
1539 case TokenIdKeywordCatch: return "catch";1538 case TokenIdKeywordCatch: return "catch";
...@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {...@@ -1558,7 +1557,6 @@ const char * token_name(TokenId id) {
1558 case TokenIdKeywordOr: return "or";1557 case TokenIdKeywordOr: return "or";
1559 case TokenIdKeywordOrElse: return "orelse";1558 case TokenIdKeywordOrElse: return "orelse";
1560 case TokenIdKeywordPacked: return "packed";1559 case TokenIdKeywordPacked: return "packed";
1561 case TokenIdKeywordPromise: return "promise";
1562 case TokenIdKeywordPub: return "pub";1560 case TokenIdKeywordPub: return "pub";
1563 case TokenIdKeywordReturn: return "return";1561 case TokenIdKeywordReturn: return "return";
1564 case TokenIdKeywordLinkSection: return "linksection";1562 case TokenIdKeywordLinkSection: return "linksection";
src/tokenizer.hpp+1-2
...@@ -53,11 +53,11 @@ enum TokenId {...@@ -53,11 +53,11 @@ enum TokenId {
53 TokenIdKeywordAlign,53 TokenIdKeywordAlign,
54 TokenIdKeywordAllowZero,54 TokenIdKeywordAllowZero,
55 TokenIdKeywordAnd,55 TokenIdKeywordAnd,
56 TokenIdKeywordAnyFrame,
56 TokenIdKeywordAsm,57 TokenIdKeywordAsm,
57 TokenIdKeywordAsync,58 TokenIdKeywordAsync,
58 TokenIdKeywordAwait,59 TokenIdKeywordAwait,
59 TokenIdKeywordBreak,60 TokenIdKeywordBreak,
60 TokenIdKeywordCancel,
61 TokenIdKeywordCatch,61 TokenIdKeywordCatch,
62 TokenIdKeywordCompTime,62 TokenIdKeywordCompTime,
63 TokenIdKeywordConst,63 TokenIdKeywordConst,
...@@ -81,7 +81,6 @@ enum TokenId {...@@ -81,7 +81,6 @@ enum TokenId {
81 TokenIdKeywordOr,81 TokenIdKeywordOr,
82 TokenIdKeywordOrElse,82 TokenIdKeywordOrElse,
83 TokenIdKeywordPacked,83 TokenIdKeywordPacked,
84 TokenIdKeywordPromise,
85 TokenIdKeywordPub,84 TokenIdKeywordPub,
86 TokenIdKeywordResume,85 TokenIdKeywordResume,
87 TokenIdKeywordReturn,86 TokenIdKeywordReturn,
src/zig_llvm.cpp+16-11
...@@ -42,7 +42,6 @@...@@ -42,7 +42,6 @@
42#include <llvm/Support/TargetRegistry.h>42#include <llvm/Support/TargetRegistry.h>
43#include <llvm/Target/TargetMachine.h>43#include <llvm/Target/TargetMachine.h>
44#include <llvm/Target/CodeGenCWrappers.h>44#include <llvm/Target/CodeGenCWrappers.h>
45#include <llvm/Transforms/Coroutines.h>
46#include <llvm/Transforms/IPO.h>45#include <llvm/Transforms/IPO.h>
47#include <llvm/Transforms/IPO/AlwaysInliner.h>46#include <llvm/Transforms/IPO/AlwaysInliner.h>
48#include <llvm/Transforms/IPO/PassManagerBuilder.h>47#include <llvm/Transforms/IPO/PassManagerBuilder.h>
...@@ -202,8 +201,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -202,8 +201,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
202 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);201 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
203 }202 }
204203
205 addCoroutinePassesToExtensionPoints(*PMBuilder);
206
207 // Set up the per-function pass manager.204 // Set up the per-function pass manager.
208 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);205 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
209 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);206 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
...@@ -797,25 +794,25 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {...@@ -797,25 +794,25 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
797 case ZigLLVM_NoSubArch:794 case ZigLLVM_NoSubArch:
798 return "";795 return "";
799 case ZigLLVM_ARMSubArch_v8_5a:796 case ZigLLVM_ARMSubArch_v8_5a:
800 return "v8_5a";797 return "v8.5a";
801 case ZigLLVM_ARMSubArch_v8_4a:798 case ZigLLVM_ARMSubArch_v8_4a:
802 return "v8_4a";799 return "v8.4a";
803 case ZigLLVM_ARMSubArch_v8_3a:800 case ZigLLVM_ARMSubArch_v8_3a:
804 return "v8_3a";801 return "v8.3a";
805 case ZigLLVM_ARMSubArch_v8_2a:802 case ZigLLVM_ARMSubArch_v8_2a:
806 return "v8_2a";803 return "v8.2a";
807 case ZigLLVM_ARMSubArch_v8_1a:804 case ZigLLVM_ARMSubArch_v8_1a:
808 return "v8_1a";805 return "v8.1a";
809 case ZigLLVM_ARMSubArch_v8:806 case ZigLLVM_ARMSubArch_v8:
810 return "v8";807 return "v8";
811 case ZigLLVM_ARMSubArch_v8r:808 case ZigLLVM_ARMSubArch_v8r:
812 return "v8r";809 return "v8r";
813 case ZigLLVM_ARMSubArch_v8m_baseline:810 case ZigLLVM_ARMSubArch_v8m_baseline:
814 return "v8m_baseline";811 return "v8m.base";
815 case ZigLLVM_ARMSubArch_v8m_mainline:812 case ZigLLVM_ARMSubArch_v8m_mainline:
816 return "v8m_mainline";813 return "v8m.main";
817 case ZigLLVM_ARMSubArch_v8_1m_mainline:814 case ZigLLVM_ARMSubArch_v8_1m_mainline:
818 return "v8_1m_mainline";815 return "v8.1m.main";
819 case ZigLLVM_ARMSubArch_v7:816 case ZigLLVM_ARMSubArch_v7:
820 return "v7";817 return "v7";
821 case ZigLLVM_ARMSubArch_v7em:818 case ZigLLVM_ARMSubArch_v7em:
...@@ -909,6 +906,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV...@@ -909,6 +906,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
909 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));906 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
910}907}
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
913class MyOStream: public raw_ostream {918class MyOStream: public raw_ostream {
914 public:919 public:
src/zig_llvm.h+2
...@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde...@@ -211,6 +211,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilde
211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);211ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
212212
213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);213ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
214ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call);
215ZIG_EXTERN_C void ZigLLVMFunctionSetPrefixData(LLVMValueRef fn, LLVMValueRef data);
214216
215ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);217ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
216ZIG_EXTERN_C void ZigLLVMAddByValAttr(LLVMValueRef fn_ref, unsigned ArgNo, LLVMTypeRef type_val);218ZIG_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;...@@ -6,3 +6,4 @@ pub const _errno = __error;
66
7pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;7pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
8pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;8pub 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(...@@ -1024,8 +1024,7 @@ pub fn openElfDebugInfo(
1024 elf_seekable_stream: *DwarfSeekableStream,1024 elf_seekable_stream: *DwarfSeekableStream,
1025 elf_in_stream: *DwarfInStream,1025 elf_in_stream: *DwarfInStream,
1026) !DwarfInfo {1026) !DwarfInfo {
1027 var efile: elf.Elf = undefined;1027 var efile = try elf.Elf.openStream(allocator, elf_seekable_stream, elf_in_stream);
1028 try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
1029 errdefer efile.close();1028 errdefer efile.close();
10301029
1031 var di = DwarfInfo{1030 var di = DwarfInfo{
std/elf.zig+6-9
...@@ -356,7 +356,6 @@ pub const SectionHeader = struct {...@@ -356,7 +356,6 @@ pub const SectionHeader = struct {
356pub const Elf = struct {356pub const Elf = struct {
357 seekable_stream: *io.SeekableStream(anyerror, anyerror),357 seekable_stream: *io.SeekableStream(anyerror, anyerror),
358 in_stream: *io.InStream(anyerror),358 in_stream: *io.InStream(anyerror),
359 auto_close_stream: bool,
360 is_64: bool,359 is_64: bool,
361 endian: builtin.Endian,360 endian: builtin.Endian,
362 file_type: FileType,361 file_type: FileType,
...@@ -368,25 +367,23 @@ pub const Elf = struct {...@@ -368,25 +367,23 @@ pub const Elf = struct {
368 string_section: *SectionHeader,367 string_section: *SectionHeader,
369 section_headers: []SectionHeader,368 section_headers: []SectionHeader,
370 allocator: *mem.Allocator,369 allocator: *mem.Allocator,
371 prealloc_file: File,
372370
373 /// Call close when done.371 /// 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 {
375 @compileError("TODO implement");373 @compileError("TODO implement");
376 }374 }
377375
378 /// Call close when done.376 /// 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 {
380 @compileError("TODO implement");378 @compileError("TODO implement");
381 }379 }
382380
383 pub fn openStream(381 pub fn openStream(
384 elf: *Elf,
385 allocator: *mem.Allocator,382 allocator: *mem.Allocator,
386 seekable_stream: *io.SeekableStream(anyerror, anyerror),383 seekable_stream: *io.SeekableStream(anyerror, anyerror),
387 in: *io.InStream(anyerror),384 in: *io.InStream(anyerror),
388 ) !void {385 ) !Elf {
389 elf.auto_close_stream = false;386 var elf: Elf = undefined;
390 elf.allocator = allocator;387 elf.allocator = allocator;
391 elf.seekable_stream = seekable_stream;388 elf.seekable_stream = seekable_stream;
392 elf.in_stream = in;389 elf.in_stream = in;
...@@ -523,12 +520,12 @@ pub const Elf = struct {...@@ -523,12 +520,12 @@ pub const Elf = struct {
523 // not a string table520 // not a string table
524 return error.InvalidFormat;521 return error.InvalidFormat;
525 }522 }
523
524 return elf;
526 }525 }
527526
528 pub fn close(elf: *Elf) void {527 pub fn close(elf: *Elf) void {
529 elf.allocator.free(elf.section_headers);528 elf.allocator.free(elf.section_headers);
530
531 if (elf.auto_close_stream) elf.prealloc_file.close();
532 }529 }
533530
534 pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {531 pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
std/event/channel.zig+45-72
...@@ -2,8 +2,6 @@ const std = @import("../std.zig");...@@ -2,8 +2,6 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const Loop = std.event.Loop;5const Loop = std.event.Loop;
86
9/// many producer, many consumer, thread-safe, runtime configurable buffer size7/// many producer, many consumer, thread-safe, runtime configurable buffer size
...@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {...@@ -77,24 +75,20 @@ pub fn Channel(comptime T: type) type {
77 /// must be called when all calls to put and get have suspended and no more calls occur75 /// must be called when all calls to put and get have suspended and no more calls occur
78 pub fn destroy(self: *SelfChannel) void {76 pub fn destroy(self: *SelfChannel) void {
79 while (self.getters.get()) |get_node| {77 while (self.getters.get()) |get_node| {
80 cancel get_node.data.tick_node.data;78 resume get_node.data.tick_node.data;
81 }79 }
82 while (self.putters.get()) |put_node| {80 while (self.putters.get()) |put_node| {
83 cancel put_node.data.tick_node.data;81 resume put_node.data.tick_node.data;
84 }82 }
85 self.loop.allocator.free(self.buffer_nodes);83 self.loop.allocator.free(self.buffer_nodes);
86 self.loop.allocator.destroy(self);84 self.loop.allocator.destroy(self);
87 }85 }
8886
89 /// puts a data item in the channel. The promise completes when the value has been added to the87 /// puts a data item in the channel. The function returns when the value has been added to the
90 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.88 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
91 pub async fn put(self: *SelfChannel, data: T) void {89 /// Or when the channel is destroyed.
92 // TODO fix this workaround90 pub fn put(self: *SelfChannel, data: T) void {
93 suspend {91 var my_tick_node = Loop.NextTickNode.init(@frame());
94 resume @handle();
95 }
96
97 var my_tick_node = Loop.NextTickNode.init(@handle());
98 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{92 var queue_node = std.atomic.Queue(PutNode).Node.init(PutNode{
99 .tick_node = &my_tick_node,93 .tick_node = &my_tick_node,
100 .data = data,94 .data = data,
...@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {...@@ -102,35 +96,29 @@ pub fn Channel(comptime T: type) type {
10296
103 // TODO test canceling a put()97 // TODO test canceling a put()
104 errdefer {98 errdefer {
105 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);99 _ = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
106 const need_dispatch = !self.putters.remove(&queue_node);100 const need_dispatch = !self.putters.remove(&queue_node);
107 self.loop.cancelOnNextTick(&my_tick_node);101 self.loop.cancelOnNextTick(&my_tick_node);
108 if (need_dispatch) {102 if (need_dispatch) {
109 // oops we made the put_count incorrect for a period of time. fix by dispatching.103 // oops we made the put_count incorrect for a period of time. fix by dispatching.
110 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);104 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
111 self.dispatch();105 self.dispatch();
112 }106 }
113 }107 }
114 suspend {108 suspend {
115 self.putters.put(&queue_node);109 self.putters.put(&queue_node);
116 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);110 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
117111
118 self.dispatch();112 self.dispatch();
119 }113 }
120 }114 }
121115
122 /// await this function to get an item from the channel. If the buffer is empty, the promise will116 /// await this function to get an item from the channel. If the buffer is empty, the frame will
123 /// complete when the next item is put in the channel.117 /// complete when the next item is put in the channel.
124 pub async fn get(self: *SelfChannel) T {118 pub async fn get(self: *SelfChannel) T {
125 // TODO fix this workaround119 // TODO https://github.com/ziglang/zig/issues/2765
126 suspend {
127 resume @handle();
128 }
129
130 // TODO integrate this function with named return values
131 // so we can get rid of this extra result copy
132 var result: T = undefined;120 var result: T = undefined;
133 var my_tick_node = Loop.NextTickNode.init(@handle());121 var my_tick_node = Loop.NextTickNode.init(@frame());
134 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{122 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
135 .tick_node = &my_tick_node,123 .tick_node = &my_tick_node,
136 .data = GetNode.Data{124 .data = GetNode.Data{
...@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {...@@ -140,19 +128,19 @@ pub fn Channel(comptime T: type) type {
140128
141 // TODO test canceling a get()129 // TODO test canceling a get()
142 errdefer {130 errdefer {
143 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);131 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
144 const need_dispatch = !self.getters.remove(&queue_node);132 const need_dispatch = !self.getters.remove(&queue_node);
145 self.loop.cancelOnNextTick(&my_tick_node);133 self.loop.cancelOnNextTick(&my_tick_node);
146 if (need_dispatch) {134 if (need_dispatch) {
147 // oops we made the get_count incorrect for a period of time. fix by dispatching.135 // oops we made the get_count incorrect for a period of time. fix by dispatching.
148 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);136 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
149 self.dispatch();137 self.dispatch();
150 }138 }
151 }139 }
152140
153 suspend {141 suspend {
154 self.getters.put(&queue_node);142 self.getters.put(&queue_node);
155 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);143 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
156144
157 self.dispatch();145 self.dispatch();
158 }146 }
...@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {...@@ -173,15 +161,10 @@ pub fn Channel(comptime T: type) type {
173 /// Await is necessary for locking purposes. The function will be resumed after checking the channel161 /// Await is necessary for locking purposes. The function will be resumed after checking the channel
174 /// for data and will not wait for data to be available.162 /// for data and will not wait for data to be available.
175 pub async fn getOrNull(self: *SelfChannel) ?T {163 pub async fn getOrNull(self: *SelfChannel) ?T {
176 // TODO fix this workaround
177 suspend {
178 resume @handle();
179 }
180
181 // TODO integrate this function with named return values164 // TODO integrate this function with named return values
182 // so we can get rid of this extra result copy165 // so we can get rid of this extra result copy
183 var result: ?T = null;166 var result: ?T = null;
184 var my_tick_node = Loop.NextTickNode.init(@handle());167 var my_tick_node = Loop.NextTickNode.init(@frame());
185 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);168 var or_null_node = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).Node.init(undefined);
186 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{169 var queue_node = std.atomic.Queue(GetNode).Node.init(GetNode{
187 .tick_node = &my_tick_node,170 .tick_node = &my_tick_node,
...@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {...@@ -197,19 +180,19 @@ pub fn Channel(comptime T: type) type {
197 // TODO test canceling getOrNull180 // TODO test canceling getOrNull
198 errdefer {181 errdefer {
199 _ = self.or_null_queue.remove(&or_null_node);182 _ = self.or_null_queue.remove(&or_null_node);
200 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);183 _ = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
201 const need_dispatch = !self.getters.remove(&queue_node);184 const need_dispatch = !self.getters.remove(&queue_node);
202 self.loop.cancelOnNextTick(&my_tick_node);185 self.loop.cancelOnNextTick(&my_tick_node);
203 if (need_dispatch) {186 if (need_dispatch) {
204 // oops we made the get_count incorrect for a period of time. fix by dispatching.187 // oops we made the get_count incorrect for a period of time. fix by dispatching.
205 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);188 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
206 self.dispatch();189 self.dispatch();
207 }190 }
208 }191 }
209192
210 suspend {193 suspend {
211 self.getters.put(&queue_node);194 self.getters.put(&queue_node);
212 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);195 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
213 self.or_null_queue.put(&or_null_node);196 self.or_null_queue.put(&or_null_node);
214197
215 self.dispatch();198 self.dispatch();
...@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {...@@ -219,21 +202,21 @@ pub fn Channel(comptime T: type) type {
219202
220 fn dispatch(self: *SelfChannel) void {203 fn dispatch(self: *SelfChannel) void {
221 // set the "need dispatch" flag204 // set the "need dispatch" flag
222 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);205 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 1, .SeqCst);
223206
224 lock: while (true) {207 lock: while (true) {
225 // set the lock flag208 // set the lock flag
226 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);209 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 1, .SeqCst);
227 if (prev_lock != 0) return;210 if (prev_lock != 0) return;
228211
229 // clear the need_dispatch flag since we're about to do it212 // clear the need_dispatch flag since we're about to do it
230 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);213 _ = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
231214
232 while (true) {215 while (true) {
233 one_dispatch: {216 one_dispatch: {
234 // later we correct these extra subtractions217 // later we correct these extra subtractions
235 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);218 var get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
236 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);219 var put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
237220
238 // transfer self.buffer to self.getters221 // transfer self.buffer to self.getters
239 while (self.buffer_len != 0) {222 while (self.buffer_len != 0) {
...@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {...@@ -252,7 +235,7 @@ pub fn Channel(comptime T: type) type {
252 self.loop.onNextTick(get_node.tick_node);235 self.loop.onNextTick(get_node.tick_node);
253 self.buffer_len -= 1;236 self.buffer_len -= 1;
254237
255 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);238 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
256 }239 }
257240
258 // direct transfer self.putters to self.getters241 // direct transfer self.putters to self.getters
...@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {...@@ -272,8 +255,8 @@ pub fn Channel(comptime T: type) type {
272 self.loop.onNextTick(get_node.tick_node);255 self.loop.onNextTick(get_node.tick_node);
273 self.loop.onNextTick(put_node.tick_node);256 self.loop.onNextTick(put_node.tick_node);
274257
275 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);258 get_count = @atomicRmw(usize, &self.get_count, .Sub, 1, .SeqCst);
276 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);259 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
277 }260 }
278261
279 // transfer self.putters to self.buffer262 // transfer self.putters to self.buffer
...@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {...@@ -285,13 +268,13 @@ pub fn Channel(comptime T: type) type {
285 self.buffer_index +%= 1;268 self.buffer_index +%= 1;
286 self.buffer_len += 1;269 self.buffer_len += 1;
287270
288 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);271 put_count = @atomicRmw(usize, &self.put_count, .Sub, 1, .SeqCst);
289 }272 }
290 }273 }
291274
292 // undo the extra subtractions275 // undo the extra subtractions
293 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);276 _ = @atomicRmw(usize, &self.get_count, .Add, 1, .SeqCst);
294 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);277 _ = @atomicRmw(usize, &self.put_count, .Add, 1, .SeqCst);
295278
296 // All the "get or null" functions should resume now.279 // All the "get or null" functions should resume now.
297 var remove_count: usize = 0;280 var remove_count: usize = 0;
...@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {...@@ -300,18 +283,18 @@ pub fn Channel(comptime T: type) type {
300 self.loop.onNextTick(or_null_node.data.data.tick_node);283 self.loop.onNextTick(or_null_node.data.data.tick_node);
301 }284 }
302 if (remove_count != 0) {285 if (remove_count != 0) {
303 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, remove_count, AtomicOrder.SeqCst);286 _ = @atomicRmw(usize, &self.get_count, .Sub, remove_count, .SeqCst);
304 }287 }
305288
306 // clear need-dispatch flag289 // clear need-dispatch flag
307 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);290 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
308 if (need_dispatch != 0) continue;291 if (need_dispatch != 0) continue;
309292
310 const my_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);293 const my_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 0, .SeqCst);
311 assert(my_lock != 0);294 assert(my_lock != 0);
312295
313 // we have to check again now that we unlocked296 // we have to check again now that we unlocked
314 if (@atomicLoad(u8, &self.need_dispatch, AtomicOrder.SeqCst) != 0) continue :lock;297 if (@atomicLoad(u8, &self.need_dispatch, .SeqCst) != 0) continue :lock;
315298
316 return;299 return;
317 }300 }
...@@ -324,51 +307,41 @@ test "std.event.Channel" {...@@ -324,51 +307,41 @@ test "std.event.Channel" {
324 // https://github.com/ziglang/zig/issues/1908307 // https://github.com/ziglang/zig/issues/1908
325 if (builtin.single_threaded) return error.SkipZigTest;308 if (builtin.single_threaded) return error.SkipZigTest;
326309
327 const allocator = std.heap.direct_allocator;
328
329 var loop: Loop = undefined;310 var loop: Loop = undefined;
330 // TODO make a multi threaded test311 // TODO make a multi threaded test
331 try loop.initSingleThreaded(allocator);312 try loop.initSingleThreaded(std.heap.direct_allocator);
332 defer loop.deinit();313 defer loop.deinit();
333314
334 const channel = try Channel(i32).create(&loop, 0);315 const channel = try Channel(i32).create(&loop, 0);
335 defer channel.destroy();316 defer channel.destroy();
336317
337 const handle = try async<allocator> testChannelGetter(&loop, channel);318 const handle = async testChannelGetter(&loop, channel);
338 defer cancel handle;319 const putter = async testChannelPutter(channel);
339
340 const putter = try async<allocator> testChannelPutter(channel);
341 defer cancel putter;
342320
343 loop.run();321 loop.run();
344}322}
345323
346async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {324async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
347 errdefer @panic("test failed");325 const value1 = channel.get();
348
349 const value1_promise = try async channel.get();
350 const value1 = await value1_promise;
351 testing.expect(value1 == 1234);326 testing.expect(value1 == 1234);
352327
353 const value2_promise = try async channel.get();328 const value2 = channel.get();
354 const value2 = await value2_promise;
355 testing.expect(value2 == 4567);329 testing.expect(value2 == 4567);
356330
357 const value3_promise = try async channel.getOrNull();331 const value3 = channel.getOrNull();
358 const value3 = await value3_promise;
359 testing.expect(value3 == null);332 testing.expect(value3 == null);
360333
361 const last_put = try async testPut(channel, 4444);334 var last_put = async testPut(channel, 4444);
362 const value4 = await try async channel.getOrNull();335 const value4 = channel.getOrNull();
363 testing.expect(value4.? == 4444);336 testing.expect(value4.? == 4444);
364 await last_put;337 await last_put;
365}338}
366339
367async fn testChannelPutter(channel: *Channel(i32)) void {340async fn testChannelPutter(channel: *Channel(i32)) void {
368 await (async channel.put(1234) catch @panic("out of memory"));341 channel.put(1234);
369 await (async channel.put(4567) catch @panic("out of memory"));342 channel.put(4567);
370}343}
371344
372async fn testPut(channel: *Channel(i32), value: i32) void {345async fn testPut(channel: *Channel(i32), value: i32) void {
373 await (async channel.put(value) catch @panic("out of memory"));346 channel.put(value);
374}347}
std/event/fs.zig+640-694
...@@ -76,17 +76,13 @@ pub const Request = struct {...@@ -76,17 +76,13 @@ pub const Request = struct {
7676
77pub const PWriteVError = error{OutOfMemory} || File.WriteError;77pub const PWriteVError = error{OutOfMemory} || File.WriteError;
7878
79/// data - just the inner references - must live until pwritev promise completes.79/// data - just the inner references - must live until pwritev frame completes.
80pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {80pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {
81 // workaround for https://github.com/ziglang/zig/issues/1194
82 suspend {
83 resume @handle();
84 }
85 switch (builtin.os) {81 switch (builtin.os) {
86 builtin.Os.macosx,82 .macosx,
87 builtin.Os.linux,83 .linux,
88 builtin.Os.freebsd,84 .freebsd,
89 builtin.Os.netbsd,85 .netbsd,
90 => {86 => {
91 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);87 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
92 defer loop.allocator.free(iovecs);88 defer loop.allocator.free(iovecs);
...@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us...@@ -100,7 +96,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
10096
101 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);97 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);
102 },98 },
103 builtin.Os.windows => {99 .windows => {
104 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);100 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);
105 defer loop.allocator.free(data_copy);101 defer loop.allocator.free(data_copy);
106 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);102 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);
...@@ -109,7 +105,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us...@@ -109,7 +105,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
109 }105 }
110}106}
111107
112/// data must outlive the returned promise108/// data must outlive the returned frame
113pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {109pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
114 if (data.len == 0) return;110 if (data.len == 0) return;
115 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);111 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);
...@@ -123,15 +119,10 @@ pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, off...@@ -123,15 +119,10 @@ pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, off
123}119}
124120
125pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {121pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {
126 // workaround for https://github.com/ziglang/zig/issues/1194
127 suspend {
128 resume @handle();
129 }
130
131 var resume_node = Loop.ResumeNode.Basic{122 var resume_node = Loop.ResumeNode.Basic{
132 .base = Loop.ResumeNode{123 .base = Loop.ResumeNode{
133 .id = Loop.ResumeNode.Id.Basic,124 .id = Loop.ResumeNode.Id.Basic,
134 .handle = @handle(),125 .handle = @frame(),
135 .overlapped = windows.OVERLAPPED{126 .overlapped = windows.OVERLAPPED{
136 .Internal = 0,127 .Internal = 0,
137 .InternalHigh = 0,128 .InternalHigh = 0,
...@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)...@@ -166,18 +157,13 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64)
166 }157 }
167}158}
168159
169/// iovecs must live until pwritev promise completes.160/// iovecs must live until pwritev frame completes.
170pub async fn pwritevPosix(161pub async fn pwritevPosix(
171 loop: *Loop,162 loop: *Loop,
172 fd: fd_t,163 fd: fd_t,
173 iovecs: []const os.iovec_const,164 iovecs: []const os.iovec_const,
174 offset: usize,165 offset: usize,
175) os.WriteError!void {166) os.WriteError!void {
176 // workaround for https://github.com/ziglang/zig/issues/1194
177 suspend {
178 resume @handle();
179 }
180
181 var req_node = RequestNode{167 var req_node = RequestNode{
182 .prev = null,168 .prev = null,
183 .next = null,169 .next = null,
...@@ -194,7 +180,7 @@ pub async fn pwritevPosix(...@@ -194,7 +180,7 @@ pub async fn pwritevPosix(
194 .TickNode = Loop.NextTickNode{180 .TickNode = Loop.NextTickNode{
195 .prev = null,181 .prev = null,
196 .next = null,182 .next = null,
197 .data = @handle(),183 .data = @frame(),
198 },184 },
199 },185 },
200 },186 },
...@@ -211,19 +197,14 @@ pub async fn pwritevPosix(...@@ -211,19 +197,14 @@ pub async fn pwritevPosix(
211197
212pub const PReadVError = error{OutOfMemory} || File.ReadError;198pub const PReadVError = error{OutOfMemory} || File.ReadError;
213199
214/// data - just the inner references - must live until preadv promise completes.200/// data - just the inner references - must live until preadv frame completes.
215pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {201pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {
216 // workaround for https://github.com/ziglang/zig/issues/1194
217 suspend {
218 resume @handle();
219 }
220
221 assert(data.len != 0);202 assert(data.len != 0);
222 switch (builtin.os) {203 switch (builtin.os) {
223 builtin.Os.macosx,204 .macosx,
224 builtin.Os.linux,205 .linux,
225 builtin.Os.freebsd,206 .freebsd,
226 builtin.Os.netbsd,207 .netbsd,
227 => {208 => {
228 const iovecs = try loop.allocator.alloc(os.iovec, data.len);209 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229 defer loop.allocator.free(iovecs);210 defer loop.allocator.free(iovecs);
...@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR...@@ -237,7 +218,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
237218
238 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);219 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);
239 },220 },
240 builtin.Os.windows => {221 .windows => {
241 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);222 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);
242 defer loop.allocator.free(data_copy);223 defer loop.allocator.free(data_copy);
243 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);224 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);
...@@ -246,7 +227,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR...@@ -246,7 +227,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
246 }227 }
247}228}
248229
249/// data must outlive the returned promise230/// data must outlive the returned frame
250pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {231pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
251 assert(data.len != 0);232 assert(data.len != 0);
252 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);233 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);
...@@ -272,15 +253,10 @@ pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u6...@@ -272,15 +253,10 @@ pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u6
272}253}
273254
274pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {255pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {
275 // workaround for https://github.com/ziglang/zig/issues/1194
276 suspend {
277 resume @handle();
278 }
279
280 var resume_node = Loop.ResumeNode.Basic{256 var resume_node = Loop.ResumeNode.Basic{
281 .base = Loop.ResumeNode{257 .base = Loop.ResumeNode{
282 .id = Loop.ResumeNode.Id.Basic,258 .id = Loop.ResumeNode.Id.Basic,
283 .handle = @handle(),259 .handle = @frame(),
284 .overlapped = windows.OVERLAPPED{260 .overlapped = windows.OVERLAPPED{
285 .Internal = 0,261 .Internal = 0,
286 .InternalHigh = 0,262 .InternalHigh = 0,
...@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize...@@ -314,18 +290,13 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize
314 return usize(bytes_transferred);290 return usize(bytes_transferred);
315}291}
316292
317/// iovecs must live until preadv promise completes293/// iovecs must live until preadv frame completes
318pub async fn preadvPosix(294pub async fn preadvPosix(
319 loop: *Loop,295 loop: *Loop,
320 fd: fd_t,296 fd: fd_t,
321 iovecs: []const os.iovec,297 iovecs: []const os.iovec,
322 offset: usize,298 offset: usize,
323) os.ReadError!usize {299) os.ReadError!usize {
324 // workaround for https://github.com/ziglang/zig/issues/1194
325 suspend {
326 resume @handle();
327 }
328
329 var req_node = RequestNode{300 var req_node = RequestNode{
330 .prev = null,301 .prev = null,
331 .next = null,302 .next = null,
...@@ -342,7 +313,7 @@ pub async fn preadvPosix(...@@ -342,7 +313,7 @@ pub async fn preadvPosix(
342 .TickNode = Loop.NextTickNode{313 .TickNode = Loop.NextTickNode{
343 .prev = null,314 .prev = null,
344 .next = null,315 .next = null,
345 .data = @handle(),316 .data = @frame(),
346 },317 },
347 },318 },
348 },319 },
...@@ -363,11 +334,6 @@ pub async fn openPosix(...@@ -363,11 +334,6 @@ pub async fn openPosix(
363 flags: u32,334 flags: u32,
364 mode: File.Mode,335 mode: File.Mode,
365) File.OpenError!fd_t {336) File.OpenError!fd_t {
366 // workaround for https://github.com/ziglang/zig/issues/1194
367 suspend {
368 resume @handle();
369 }
370
371 const path_c = try std.os.toPosixPath(path);337 const path_c = try std.os.toPosixPath(path);
372338
373 var req_node = RequestNode{339 var req_node = RequestNode{
...@@ -386,7 +352,7 @@ pub async fn openPosix(...@@ -386,7 +352,7 @@ pub async fn openPosix(
386 .TickNode = Loop.NextTickNode{352 .TickNode = Loop.NextTickNode{
387 .prev = null,353 .prev = null,
388 .next = null,354 .next = null,
389 .data = @handle(),355 .data = @frame(),
390 },356 },
391 },357 },
392 },358 },
...@@ -403,12 +369,12 @@ pub async fn openPosix(...@@ -403,12 +369,12 @@ pub async fn openPosix(
403369
404pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {370pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
405 switch (builtin.os) {371 switch (builtin.os) {
406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {372 .macosx, .linux, .freebsd, .netbsd => {
407 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;373 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
408 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);374 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
409 },375 },
410376
411 builtin.Os.windows => return windows.CreateFile(377 .windows => return windows.CreateFile(
412 path,378 path,
413 windows.GENERIC_READ,379 windows.GENERIC_READ,
414 windows.FILE_SHARE_READ,380 windows.FILE_SHARE_READ,
...@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {...@@ -431,15 +397,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
431/// Creates if does not exist. Truncates the file if it exists.397/// Creates if does not exist. Truncates the file if it exists.
432pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {398pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
433 switch (builtin.os) {399 switch (builtin.os) {
434 builtin.Os.macosx,400 .macosx,
435 builtin.Os.linux,401 .linux,
436 builtin.Os.freebsd,402 .freebsd,
437 builtin.Os.netbsd,403 .netbsd,
438 => {404 => {
439 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;405 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
440 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);406 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
441 },407 },
442 builtin.Os.windows => return windows.CreateFile(408 .windows => return windows.CreateFile(
443 path,409 path,
444 windows.GENERIC_WRITE,410 windows.GENERIC_WRITE,
445 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,411 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -459,12 +425,12 @@ pub async fn openReadWrite(...@@ -459,12 +425,12 @@ pub async fn openReadWrite(
459 mode: File.Mode,425 mode: File.Mode,
460) File.OpenError!fd_t {426) File.OpenError!fd_t {
461 switch (builtin.os) {427 switch (builtin.os) {
462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {428 .macosx, .linux, .freebsd, .netbsd => {
463 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;429 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
464 return await (async openPosix(loop, path, flags, mode) catch unreachable);430 return await (async openPosix(loop, path, flags, mode) catch unreachable);
465 },431 },
466432
467 builtin.Os.windows => return windows.CreateFile(433 .windows => return windows.CreateFile(
468 path,434 path,
469 windows.GENERIC_WRITE | windows.GENERIC_READ,435 windows.GENERIC_WRITE | windows.GENERIC_READ,
470 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,436 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -489,9 +455,9 @@ pub const CloseOperation = struct {...@@ -489,9 +455,9 @@ pub const CloseOperation = struct {
489 os_data: OsData,455 os_data: OsData,
490456
491 const OsData = switch (builtin.os) {457 const OsData = switch (builtin.os) {
492 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,458 .linux, .macosx, .freebsd, .netbsd => OsDataPosix,
493459
494 builtin.Os.windows => struct {460 .windows => struct {
495 handle: ?fd_t,461 handle: ?fd_t,
496 },462 },
497463
...@@ -508,8 +474,8 @@ pub const CloseOperation = struct {...@@ -508,8 +474,8 @@ pub const CloseOperation = struct {
508 self.* = CloseOperation{474 self.* = CloseOperation{
509 .loop = loop,475 .loop = loop,
510 .os_data = switch (builtin.os) {476 .os_data = switch (builtin.os) {
511 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),477 .linux, .macosx, .freebsd, .netbsd => initOsDataPosix(self),
512 builtin.Os.windows => OsData{ .handle = null },478 .windows => OsData{ .handle = null },
513 else => @compileError("Unsupported OS"),479 else => @compileError("Unsupported OS"),
514 },480 },
515 };481 };
...@@ -535,10 +501,10 @@ pub const CloseOperation = struct {...@@ -535,10 +501,10 @@ pub const CloseOperation = struct {
535 /// Defer this after creating.501 /// Defer this after creating.
536 pub fn finish(self: *CloseOperation) void {502 pub fn finish(self: *CloseOperation) void {
537 switch (builtin.os) {503 switch (builtin.os) {
538 builtin.Os.linux,504 .linux,
539 builtin.Os.macosx,505 .macosx,
540 builtin.Os.freebsd,506 .freebsd,
541 builtin.Os.netbsd,507 .netbsd,
542 => {508 => {
543 if (self.os_data.have_fd) {509 if (self.os_data.have_fd) {
544 self.loop.posixFsRequest(&self.os_data.close_req_node);510 self.loop.posixFsRequest(&self.os_data.close_req_node);
...@@ -546,7 +512,7 @@ pub const CloseOperation = struct {...@@ -546,7 +512,7 @@ pub const CloseOperation = struct {
546 self.loop.allocator.destroy(self);512 self.loop.allocator.destroy(self);
547 }513 }
548 },514 },
549 builtin.Os.windows => {515 .windows => {
550 if (self.os_data.handle) |handle| {516 if (self.os_data.handle) |handle| {
551 os.close(handle);517 os.close(handle);
552 }518 }
...@@ -558,15 +524,15 @@ pub const CloseOperation = struct {...@@ -558,15 +524,15 @@ pub const CloseOperation = struct {
558524
559 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {525 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
560 switch (builtin.os) {526 switch (builtin.os) {
561 builtin.Os.linux,527 .linux,
562 builtin.Os.macosx,528 .macosx,
563 builtin.Os.freebsd,529 .freebsd,
564 builtin.Os.netbsd,530 .netbsd,
565 => {531 => {
566 self.os_data.close_req_node.data.msg.Close.fd = handle;532 self.os_data.close_req_node.data.msg.Close.fd = handle;
567 self.os_data.have_fd = true;533 self.os_data.have_fd = true;
568 },534 },
569 builtin.Os.windows => {535 .windows => {
570 self.os_data.handle = handle;536 self.os_data.handle = handle;
571 },537 },
572 else => @compileError("Unsupported OS"),538 else => @compileError("Unsupported OS"),
...@@ -576,14 +542,14 @@ pub const CloseOperation = struct {...@@ -576,14 +542,14 @@ pub const CloseOperation = struct {
576 /// Undo a `setHandle`.542 /// Undo a `setHandle`.
577 pub fn clearHandle(self: *CloseOperation) void {543 pub fn clearHandle(self: *CloseOperation) void {
578 switch (builtin.os) {544 switch (builtin.os) {
579 builtin.Os.linux,545 .linux,
580 builtin.Os.macosx,546 .macosx,
581 builtin.Os.freebsd,547 .freebsd,
582 builtin.Os.netbsd,548 .netbsd,
583 => {549 => {
584 self.os_data.have_fd = false;550 self.os_data.have_fd = false;
585 },551 },
586 builtin.Os.windows => {552 .windows => {
587 self.os_data.handle = null;553 self.os_data.handle = null;
588 },554 },
589 else => @compileError("Unsupported OS"),555 else => @compileError("Unsupported OS"),
...@@ -592,15 +558,15 @@ pub const CloseOperation = struct {...@@ -592,15 +558,15 @@ pub const CloseOperation = struct {
592558
593 pub fn getHandle(self: *CloseOperation) fd_t {559 pub fn getHandle(self: *CloseOperation) fd_t {
594 switch (builtin.os) {560 switch (builtin.os) {
595 builtin.Os.linux,561 .linux,
596 builtin.Os.macosx,562 .macosx,
597 builtin.Os.freebsd,563 .freebsd,
598 builtin.Os.netbsd,564 .netbsd,
599 => {565 => {
600 assert(self.os_data.have_fd);566 assert(self.os_data.have_fd);
601 return self.os_data.close_req_node.data.msg.Close.fd;567 return self.os_data.close_req_node.data.msg.Close.fd;
602 },568 },
603 builtin.Os.windows => {569 .windows => {
604 return self.os_data.handle.?;570 return self.os_data.handle.?;
605 },571 },
606 else => @compileError("Unsupported OS"),572 else => @compileError("Unsupported OS"),
...@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi...@@ -617,12 +583,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi
617/// contents must remain alive until writeFile completes.583/// contents must remain alive until writeFile completes.
618pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {584pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
619 switch (builtin.os) {585 switch (builtin.os) {
620 builtin.Os.linux,586 .linux,
621 builtin.Os.macosx,587 .macosx,
622 builtin.Os.freebsd,588 .freebsd,
623 builtin.Os.netbsd,589 .netbsd,
624 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),590 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
625 builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),591 .windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
626 else => @compileError("Unsupported OS"),592 else => @compileError("Unsupported OS"),
627 }593 }
628}594}
...@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !...@@ -643,11 +609,6 @@ async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !
643}609}
644610
645async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {611async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
646 // workaround for https://github.com/ziglang/zig/issues/1194
647 suspend {
648 resume @handle();
649 }
650
651 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);612 const path_with_null = try std.cstr.addNullByte(loop.allocator, path);
652 defer loop.allocator.free(path_with_null);613 defer loop.allocator.free(path_with_null);
653614
...@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8...@@ -667,7 +628,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
667 .TickNode = Loop.NextTickNode{628 .TickNode = Loop.NextTickNode{
668 .prev = null,629 .prev = null,
669 .next = null,630 .next = null,
670 .data = @handle(),631 .data = @frame(),
671 },632 },
672 },633 },
673 },634 },
...@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8...@@ -682,7 +643,7 @@ async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8
682 return req_node.data.msg.WriteFile.result;643 return req_node.data.msg.WriteFile.result;
683}644}
684645
685/// The promise resumes when the last data has been confirmed written, but before the file handle646/// The frame resumes when the last data has been confirmed written, but before the file handle
686/// is closed.647/// is closed.
687/// Caller owns returned memory.648/// Caller owns returned memory.
688pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {649pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8 {
...@@ -715,598 +676,583 @@ pub const WatchEventId = enum {...@@ -715,598 +676,583 @@ pub const WatchEventId = enum {
715 Delete,676 Delete,
716};677};
717678
718pub const WatchEventError = error{679//pub const WatchEventError = error{
719 UserResourceLimitReached,680// UserResourceLimitReached,
720 SystemResources,681// SystemResources,
721 AccessDenied,682// AccessDenied,
722 Unexpected, // TODO remove this possibility683// Unexpected, // TODO remove this possibility
723};684//};
724685//
725pub fn Watch(comptime V: type) type {686//pub fn Watch(comptime V: type) type {
726 return struct {687// return struct {
727 channel: *event.Channel(Event.Error!Event),688// channel: *event.Channel(Event.Error!Event),
728 os_data: OsData,689// os_data: OsData,
729690//
730 const OsData = switch (builtin.os) {691// const OsData = switch (builtin.os) {
731 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {692// .macosx, .freebsd, .netbsd => struct {
732 file_table: FileTable,693// file_table: FileTable,
733 table_lock: event.Lock,694// table_lock: event.Lock,
734695//
735 const FileTable = std.AutoHashMap([]const u8, *Put);696// const FileTable = std.AutoHashMap([]const u8, *Put);
736 const Put = struct {697// const Put = struct {
737 putter: promise,698// putter: anyframe,
738 value_ptr: *V,699// value_ptr: *V,
739 };700// };
740 },701// },
741702//
742 builtin.Os.linux => LinuxOsData,703// .linux => LinuxOsData,
743 builtin.Os.windows => WindowsOsData,704// .windows => WindowsOsData,
744705//
745 else => @compileError("Unsupported OS"),706// else => @compileError("Unsupported OS"),
746 };707// };
747708//
748 const WindowsOsData = struct {709// const WindowsOsData = struct {
749 table_lock: event.Lock,710// table_lock: event.Lock,
750 dir_table: DirTable,711// dir_table: DirTable,
751 all_putters: std.atomic.Queue(promise),712// all_putters: std.atomic.Queue(anyframe),
752 ref_count: std.atomic.Int(usize),713// ref_count: std.atomic.Int(usize),
753714//
754 const DirTable = std.AutoHashMap([]const u8, *Dir);715// const DirTable = std.AutoHashMap([]const u8, *Dir);
755 const FileTable = std.AutoHashMap([]const u16, V);716// const FileTable = std.AutoHashMap([]const u16, V);
756717//
757 const Dir = struct {718// const Dir = struct {
758 putter: promise,719// putter: anyframe,
759 file_table: FileTable,720// file_table: FileTable,
760 table_lock: event.Lock,721// table_lock: event.Lock,
761 };722// };
762 };723// };
763724//
764 const LinuxOsData = struct {725// const LinuxOsData = struct {
765 putter: promise,726// putter: anyframe,
766 inotify_fd: i32,727// inotify_fd: i32,
767 wd_table: WdTable,728// wd_table: WdTable,
768 table_lock: event.Lock,729// table_lock: event.Lock,
769730//
770 const WdTable = std.AutoHashMap(i32, Dir);731// const WdTable = std.AutoHashMap(i32, Dir);
771 const FileTable = std.AutoHashMap([]const u8, V);732// const FileTable = std.AutoHashMap([]const u8, V);
772733//
773 const Dir = struct {734// const Dir = struct {
774 dirname: []const u8,735// dirname: []const u8,
775 file_table: FileTable,736// file_table: FileTable,
776 };737// };
777 };738// };
778739//
779 const FileToHandle = std.AutoHashMap([]const u8, promise);740// const FileToHandle = std.AutoHashMap([]const u8, anyframe);
780741//
781 const Self = @This();742// const Self = @This();
782743//
783 pub const Event = struct {744// pub const Event = struct {
784 id: Id,745// id: Id,
785 data: V,746// data: V,
786747//
787 pub const Id = WatchEventId;748// pub const Id = WatchEventId;
788 pub const Error = WatchEventError;749// pub const Error = WatchEventError;
789 };750// };
790751//
791 pub fn create(loop: *Loop, event_buf_count: usize) !*Self {752// pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
792 const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);753// const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
793 errdefer channel.destroy();754// errdefer channel.destroy();
794755//
795 switch (builtin.os) {756// switch (builtin.os) {
796 builtin.Os.linux => {757// .linux => {
797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);758// const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
798 errdefer os.close(inotify_fd);759// errdefer os.close(inotify_fd);
799760//
800 var result: *Self = undefined;761// var result: *Self = undefined;
801 _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);762// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
802 return result;763// return result;
803 },764// },
804765//
805 builtin.Os.windows => {766// .windows => {
806 const self = try loop.allocator.create(Self);767// const self = try loop.allocator.create(Self);
807 errdefer loop.allocator.destroy(self);768// errdefer loop.allocator.destroy(self);
808 self.* = Self{769// self.* = Self{
809 .channel = channel,770// .channel = channel,
810 .os_data = OsData{771// .os_data = OsData{
811 .table_lock = event.Lock.init(loop),772// .table_lock = event.Lock.init(loop),
812 .dir_table = OsData.DirTable.init(loop.allocator),773// .dir_table = OsData.DirTable.init(loop.allocator),
813 .ref_count = std.atomic.Int(usize).init(1),774// .ref_count = std.atomic.Int(usize).init(1),
814 .all_putters = std.atomic.Queue(promise).init(),775// .all_putters = std.atomic.Queue(anyframe).init(),
815 },776// },
816 };777// };
817 return self;778// return self;
818 },779// },
819780//
820 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {781// .macosx, .freebsd, .netbsd => {
821 const self = try loop.allocator.create(Self);782// const self = try loop.allocator.create(Self);
822 errdefer loop.allocator.destroy(self);783// errdefer loop.allocator.destroy(self);
823784//
824 self.* = Self{785// self.* = Self{
825 .channel = channel,786// .channel = channel,
826 .os_data = OsData{787// .os_data = OsData{
827 .table_lock = event.Lock.init(loop),788// .table_lock = event.Lock.init(loop),
828 .file_table = OsData.FileTable.init(loop.allocator),789// .file_table = OsData.FileTable.init(loop.allocator),
829 },790// },
830 };791// };
831 return self;792// return self;
832 },793// },
833 else => @compileError("Unsupported OS"),794// else => @compileError("Unsupported OS"),
834 }795// }
835 }796// }
836797//
837 /// All addFile calls and removeFile calls must have completed.798// /// All addFile calls and removeFile calls must have completed.
838 pub fn destroy(self: *Self) void {799// pub fn destroy(self: *Self) void {
839 switch (builtin.os) {800// switch (builtin.os) {
840 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {801// .macosx, .freebsd, .netbsd => {
841 // TODO we need to cancel the coroutines before destroying the lock802// // TODO we need to cancel the frames before destroying the lock
842 self.os_data.table_lock.deinit();803// self.os_data.table_lock.deinit();
843 var it = self.os_data.file_table.iterator();804// var it = self.os_data.file_table.iterator();
844 while (it.next()) |entry| {805// while (it.next()) |entry| {
845 cancel entry.value.putter;806// cancel entry.value.putter;
846 self.channel.loop.allocator.free(entry.key);807// self.channel.loop.allocator.free(entry.key);
847 }808// }
848 self.channel.destroy();809// self.channel.destroy();
849 },810// },
850 builtin.Os.linux => cancel self.os_data.putter,811// .linux => cancel self.os_data.putter,
851 builtin.Os.windows => {812// .windows => {
852 while (self.os_data.all_putters.get()) |putter_node| {813// while (self.os_data.all_putters.get()) |putter_node| {
853 cancel putter_node.data;814// cancel putter_node.data;
854 }815// }
855 self.deref();816// self.deref();
856 },817// },
857 else => @compileError("Unsupported OS"),818// else => @compileError("Unsupported OS"),
858 }819// }
859 }820// }
860821//
861 fn ref(self: *Self) void {822// fn ref(self: *Self) void {
862 _ = self.os_data.ref_count.incr();823// _ = self.os_data.ref_count.incr();
863 }824// }
864825//
865 fn deref(self: *Self) void {826// fn deref(self: *Self) void {
866 if (self.os_data.ref_count.decr() == 1) {827// if (self.os_data.ref_count.decr() == 1) {
867 const allocator = self.channel.loop.allocator;828// const allocator = self.channel.loop.allocator;
868 self.os_data.table_lock.deinit();829// self.os_data.table_lock.deinit();
869 var it = self.os_data.dir_table.iterator();830// var it = self.os_data.dir_table.iterator();
870 while (it.next()) |entry| {831// while (it.next()) |entry| {
871 allocator.free(entry.key);832// allocator.free(entry.key);
872 allocator.destroy(entry.value);833// allocator.destroy(entry.value);
873 }834// }
874 self.os_data.dir_table.deinit();835// self.os_data.dir_table.deinit();
875 self.channel.destroy();836// self.channel.destroy();
876 allocator.destroy(self);837// allocator.destroy(self);
877 }838// }
878 }839// }
879840//
880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {841// pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
881 switch (builtin.os) {842// switch (builtin.os) {
882 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),843// .macosx, .freebsd, .netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),844// .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),845// .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),846// else => @compileError("Unsupported OS"),
886 }847// }
887 }848// }
888849//
889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {850// async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});851// const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
891 var resolved_path_consumed = false;852// var resolved_path_consumed = false;
892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);853// defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
893854//
894 var close_op = try CloseOperation.start(self.channel.loop);855// var close_op = try CloseOperation.start(self.channel.loop);
895 var close_op_consumed = false;856// var close_op_consumed = false;
896 defer if (!close_op_consumed) close_op.finish();857// defer if (!close_op_consumed) close_op.finish();
897858//
898 const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;859// const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
899 const mode = 0;860// const mode = 0;
900 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);861// const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
901 close_op.setHandle(fd);862// close_op.setHandle(fd);
902863//
903 var put_data: *OsData.Put = undefined;864// var put_data: *OsData.Put = undefined;
904 const putter = try async self.kqPutEvents(close_op, value, &put_data);865// const putter = try async self.kqPutEvents(close_op, value, &put_data);
905 close_op_consumed = true;866// close_op_consumed = true;
906 errdefer cancel putter;867// errdefer cancel putter;
907868//
908 const result = blk: {869// const result = blk: {
909 const held = await (async self.os_data.table_lock.acquire() catch unreachable);870// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
910 defer held.release();871// defer held.release();
911872//
912 const gop = try self.os_data.file_table.getOrPut(resolved_path);873// const gop = try self.os_data.file_table.getOrPut(resolved_path);
913 if (gop.found_existing) {874// if (gop.found_existing) {
914 const prev_value = gop.kv.value.value_ptr.*;875// const prev_value = gop.kv.value.value_ptr.*;
915 cancel gop.kv.value.putter;876// cancel gop.kv.value.putter;
916 gop.kv.value = put_data;877// gop.kv.value = put_data;
917 break :blk prev_value;878// break :blk prev_value;
918 } else {879// } else {
919 resolved_path_consumed = true;880// resolved_path_consumed = true;
920 gop.kv.value = put_data;881// gop.kv.value = put_data;
921 break :blk null;882// break :blk null;
922 }883// }
923 };884// };
924885//
925 return result;886// return result;
926 }887// }
927888//
928 async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {889// async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
929 // TODO https://github.com/ziglang/zig/issues/1194890// var value_copy = value;
930 suspend {891// var put = OsData.Put{
931 resume @handle();892// .putter = @frame(),
932 }893// .value_ptr = &value_copy,
933894// };
934 var value_copy = value;895// out_put.* = &put;
935 var put = OsData.Put{896// self.channel.loop.beginOneEvent();
936 .putter = @handle(),897//
937 .value_ptr = &value_copy,898// defer {
938 };899// close_op.finish();
939 out_put.* = &put;900// self.channel.loop.finishOneEvent();
940 self.channel.loop.beginOneEvent();901// }
941902//
942 defer {903// while (true) {
943 close_op.finish();904// if (await (async self.channel.loop.bsdWaitKev(
944 self.channel.loop.finishOneEvent();905// @intCast(usize, close_op.getHandle()),
945 }906// os.EVFILT_VNODE,
946907// os.NOTE_WRITE | os.NOTE_DELETE,
947 while (true) {908// ) catch unreachable)) |kev| {
948 if (await (async self.channel.loop.bsdWaitKev(909// // TODO handle EV_ERROR
949 @intCast(usize, close_op.getHandle()),910// if (kev.fflags & os.NOTE_DELETE != 0) {
950 os.EVFILT_VNODE,911// await (async self.channel.put(Self.Event{
951 os.NOTE_WRITE | os.NOTE_DELETE,912// .id = Event.Id.Delete,
952 ) catch unreachable)) |kev| {913// .data = value_copy,
953 // TODO handle EV_ERROR914// }) catch unreachable);
954 if (kev.fflags & os.NOTE_DELETE != 0) {915// } else if (kev.fflags & os.NOTE_WRITE != 0) {
955 await (async self.channel.put(Self.Event{916// await (async self.channel.put(Self.Event{
956 .id = Event.Id.Delete,917// .id = Event.Id.CloseWrite,
957 .data = value_copy,918// .data = value_copy,
958 }) catch unreachable);919// }) catch unreachable);
959 } else if (kev.fflags & os.NOTE_WRITE != 0) {920// }
960 await (async self.channel.put(Self.Event{921// } else |err| switch (err) {
961 .id = Event.Id.CloseWrite,922// error.EventNotFound => unreachable,
962 .data = value_copy,923// error.ProcessNotFound => unreachable,
963 }) catch unreachable);924// error.Overflow => unreachable,
964 }925// error.AccessDenied, error.SystemResources => |casted_err| {
965 } else |err| switch (err) {926// await (async self.channel.put(casted_err) catch unreachable);
966 error.EventNotFound => unreachable,927// },
967 error.ProcessNotFound => unreachable,928// }
968 error.Overflow => unreachable,929// }
969 error.AccessDenied, error.SystemResources => |casted_err| {930// }
970 await (async self.channel.put(casted_err) catch unreachable);931//
971 },932// async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
972 }933// const value_copy = value;
973 }934//
974 }935// const dirname = std.fs.path.dirname(file_path) orelse ".";
975936// const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {937// var dirname_with_null_consumed = false;
977 const value_copy = value;938// defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
978939//
979 const dirname = std.fs.path.dirname(file_path) orelse ".";940// const basename = std.fs.path.basename(file_path);
980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);941// const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
981 var dirname_with_null_consumed = false;942// var basename_with_null_consumed = false;
982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);943// defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
983944//
984 const basename = std.fs.path.basename(file_path);945// const wd = try os.inotify_add_watchC(
985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);946// self.os_data.inotify_fd,
986 var basename_with_null_consumed = false;947// dirname_with_null.ptr,
987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);948// os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
988949// );
989 const wd = try os.inotify_add_watchC(950// // wd is either a newly created watch or an existing one.
990 self.os_data.inotify_fd,951//
991 dirname_with_null.ptr,952// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
992 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,953// defer held.release();
993 );954//
994 // wd is either a newly created watch or an existing one.955// const gop = try self.os_data.wd_table.getOrPut(wd);
995956// if (!gop.found_existing) {
996 const held = await (async self.os_data.table_lock.acquire() catch unreachable);957// gop.kv.value = OsData.Dir{
997 defer held.release();958// .dirname = dirname_with_null,
998959// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
999 const gop = try self.os_data.wd_table.getOrPut(wd);960// };
1000 if (!gop.found_existing) {961// dirname_with_null_consumed = true;
1001 gop.kv.value = OsData.Dir{962// }
1002 .dirname = dirname_with_null,963// const dir = &gop.kv.value;
1003 .file_table = OsData.FileTable.init(self.channel.loop.allocator),964//
1004 };965// const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
1005 dirname_with_null_consumed = true;966// if (file_table_gop.found_existing) {
1006 }967// const prev_value = file_table_gop.kv.value;
1007 const dir = &gop.kv.value;968// file_table_gop.kv.value = value_copy;
1008969// return prev_value;
1009 const file_table_gop = try dir.file_table.getOrPut(basename_with_null);970// } else {
1010 if (file_table_gop.found_existing) {971// file_table_gop.kv.value = value_copy;
1011 const prev_value = file_table_gop.kv.value;972// basename_with_null_consumed = true;
1012 file_table_gop.kv.value = value_copy;973// return null;
1013 return prev_value;974// }
1014 } else {975// }
1015 file_table_gop.kv.value = value_copy;976//
1016 basename_with_null_consumed = true;977// async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
1017 return null;978// const value_copy = value;
1018 }979// // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
1019 }980//
1020981// const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1021 async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {982// var dirname_consumed = false;
1022 const value_copy = value;983// defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)984//
1024985// const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");986// defer self.channel.loop.allocator.free(dirname_utf16le);
1026 var dirname_consumed = false;987//
1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);988// // TODO https://github.com/ziglang/zig/issues/265
1028989// const basename = std.fs.path.basename(file_path);
1029 const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);990// const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1030 defer self.channel.loop.allocator.free(dirname_utf16le);991// var basename_utf16le_null_consumed = false;
1031992// defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1032 // TODO https://github.com/ziglang/zig/issues/265993// const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
1033 const basename = std.fs.path.basename(file_path);994//
1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);995// const dir_handle = try windows.CreateFileW(
1035 var basename_utf16le_null_consumed = false;996// dirname_utf16le.ptr,
1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);997// windows.FILE_LIST_DIRECTORY,
1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];998// windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
1038999// null,
1039 const dir_handle = try windows.CreateFileW(1000// windows.OPEN_EXISTING,
1040 dirname_utf16le.ptr,1001// windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1041 windows.FILE_LIST_DIRECTORY,1002// null,
1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,1003// );
1043 null,1004// var dir_handle_consumed = false;
1044 windows.OPEN_EXISTING,1005// defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,1006//
1046 null,1007// const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1047 );1008// defer held.release();
1048 var dir_handle_consumed = false;1009//
1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);1010// const gop = try self.os_data.dir_table.getOrPut(dirname);
10501011// if (gop.found_existing) {
1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);1012// const dir = gop.kv.value;
1052 defer held.release();1013// const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
10531014// defer held_dir_lock.release();
1054 const gop = try self.os_data.dir_table.getOrPut(dirname);1015//
1055 if (gop.found_existing) {1016// const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1056 const dir = gop.kv.value;1017// if (file_gop.found_existing) {
1057 const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);1018// const prev_value = file_gop.kv.value;
1058 defer held_dir_lock.release();1019// file_gop.kv.value = value_copy;
10591020// return prev_value;
1060 const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);1021// } else {
1061 if (file_gop.found_existing) {1022// file_gop.kv.value = value_copy;
1062 const prev_value = file_gop.kv.value;1023// basename_utf16le_null_consumed = true;
1063 file_gop.kv.value = value_copy;1024// return null;
1064 return prev_value;1025// }
1065 } else {1026// } else {
1066 file_gop.kv.value = value_copy;1027// errdefer _ = self.os_data.dir_table.remove(dirname);
1067 basename_utf16le_null_consumed = true;1028// const dir = try self.channel.loop.allocator.create(OsData.Dir);
1068 return null;1029// errdefer self.channel.loop.allocator.destroy(dir);
1069 }1030//
1070 } else {1031// dir.* = OsData.Dir{
1071 errdefer _ = self.os_data.dir_table.remove(dirname);1032// .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1072 const dir = try self.channel.loop.allocator.create(OsData.Dir);1033// .table_lock = event.Lock.init(self.channel.loop),
1073 errdefer self.channel.loop.allocator.destroy(dir);1034// .putter = undefined,
10741035// };
1075 dir.* = OsData.Dir{1036// gop.kv.value = dir;
1076 .file_table = OsData.FileTable.init(self.channel.loop.allocator),1037// assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1077 .table_lock = event.Lock.init(self.channel.loop),1038// basename_utf16le_null_consumed = true;
1078 .putter = undefined,1039//
1079 };1040// dir.putter = try async self.windowsDirReader(dir_handle, dir);
1080 gop.kv.value = dir;1041// dir_handle_consumed = true;
1081 assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);1042//
1082 basename_utf16le_null_consumed = true;1043// dirname_consumed = true;
10831044//
1084 dir.putter = try async self.windowsDirReader(dir_handle, dir);1045// return null;
1085 dir_handle_consumed = true;1046// }
10861047// }
1087 dirname_consumed = true;1048//
10881049// async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1089 return null;1050// self.ref();
1090 }1051// defer self.deref();
1091 }1052//
10921053// defer os.close(dir_handle);
1093 async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {1054//
1094 // TODO https://github.com/ziglang/zig/issues/11941055// var putter_node = std.atomic.Queue(anyframe).Node{
1095 suspend {1056// .data = @frame(),
1096 resume @handle();1057// .prev = null,
1097 }1058// .next = null,
10981059// };
1099 self.ref();1060// self.os_data.all_putters.put(&putter_node);
1100 defer self.deref();1061// defer _ = self.os_data.all_putters.remove(&putter_node);
11011062//
1102 defer os.close(dir_handle);1063// var resume_node = Loop.ResumeNode.Basic{
11031064// .base = Loop.ResumeNode{
1104 var putter_node = std.atomic.Queue(promise).Node{1065// .id = Loop.ResumeNode.Id.Basic,
1105 .data = @handle(),1066// .handle = @frame(),
1106 .prev = null,1067// .overlapped = windows.OVERLAPPED{
1107 .next = null,1068// .Internal = 0,
1108 };1069// .InternalHigh = 0,
1109 self.os_data.all_putters.put(&putter_node);1070// .Offset = 0,
1110 defer _ = self.os_data.all_putters.remove(&putter_node);1071// .OffsetHigh = 0,
11111072// .hEvent = null,
1112 var resume_node = Loop.ResumeNode.Basic{1073// },
1113 .base = Loop.ResumeNode{1074// },
1114 .id = Loop.ResumeNode.Id.Basic,1075// };
1115 .handle = @handle(),1076// var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1116 .overlapped = windows.OVERLAPPED{1077//
1117 .Internal = 0,1078// // TODO handle this error not in the channel but in the setup
1118 .InternalHigh = 0,1079// _ = windows.CreateIoCompletionPort(
1119 .Offset = 0,1080// dir_handle,
1120 .OffsetHigh = 0,1081// self.channel.loop.os_data.io_port,
1121 .hEvent = null,1082// undefined,
1122 },1083// undefined,
1123 },1084// ) catch |err| {
1124 };1085// await (async self.channel.put(err) catch unreachable);
1125 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;1086// return;
11261087// };
1127 // TODO handle this error not in the channel but in the setup1088//
1128 _ = windows.CreateIoCompletionPort(1089// while (true) {
1129 dir_handle,1090// {
1130 self.channel.loop.os_data.io_port,1091// // TODO only 1 beginOneEvent for the whole function
1131 undefined,1092// self.channel.loop.beginOneEvent();
1132 undefined,1093// errdefer self.channel.loop.finishOneEvent();
1133 ) catch |err| {1094// errdefer {
1134 await (async self.channel.put(err) catch unreachable);1095// _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1135 return;1096// }
1136 };1097// suspend {
11371098// _ = windows.kernel32.ReadDirectoryChangesW(
1138 while (true) {1099// dir_handle,
1139 {1100// &event_buf,
1140 // TODO only 1 beginOneEvent for the whole coroutine1101// @intCast(windows.DWORD, event_buf.len),
1141 self.channel.loop.beginOneEvent();1102// windows.FALSE, // watch subtree
1142 errdefer self.channel.loop.finishOneEvent();1103// windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1143 errdefer {1104// windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1144 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);1105// windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1145 }1106// windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1146 suspend {1107// null, // number of bytes transferred (unused for async)
1147 _ = windows.kernel32.ReadDirectoryChangesW(1108// &resume_node.base.overlapped,
1148 dir_handle,1109// null, // completion routine - unused because we use IOCP
1149 &event_buf,1110// );
1150 @intCast(windows.DWORD, event_buf.len),1111// }
1151 windows.FALSE, // watch subtree1112// }
1152 windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |1113// var bytes_transferred: windows.DWORD = undefined;
1153 windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |1114// if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1154 windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |1115// const err = switch (windows.kernel32.GetLastError()) {
1155 windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,1116// else => |err| windows.unexpectedError(err),
1156 null, // number of bytes transferred (unused for async)1117// };
1157 &resume_node.base.overlapped,1118// await (async self.channel.put(err) catch unreachable);
1158 null, // completion routine - unused because we use IOCP1119// } else {
1159 );1120// // can't use @bytesToSlice because of the special variable length name field
1160 }1121// var ptr = event_buf[0..].ptr;
1161 }1122// const end_ptr = ptr + bytes_transferred;
1162 var bytes_transferred: windows.DWORD = undefined;1123// var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1163 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {1124// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1164 const err = switch (windows.kernel32.GetLastError()) {1125// ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1165 else => |err| windows.unexpectedError(err),1126// const emit = switch (ev.Action) {
1166 };1127// windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1167 await (async self.channel.put(err) catch unreachable);1128// windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1168 } else {1129// else => null,
1169 // can't use @bytesToSlice because of the special variable length name field1130// };
1170 var ptr = event_buf[0..].ptr;1131// if (emit) |id| {
1171 const end_ptr = ptr + bytes_transferred;1132// const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1172 var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;1133// const user_value = blk: {
1173 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {1134// const held = await (async dir.table_lock.acquire() catch unreachable);
1174 ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);1135// defer held.release();
1175 const emit = switch (ev.Action) {1136//
1176 windows.FILE_ACTION_REMOVED => WatchEventId.Delete,1137// if (dir.file_table.get(basename_utf16le)) |entry| {
1177 windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,1138// break :blk entry.value;
1178 else => null,1139// } else {
1179 };1140// break :blk null;
1180 if (emit) |id| {1141// }
1181 const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];1142// };
1182 const user_value = blk: {1143// if (user_value) |v| {
1183 const held = await (async dir.table_lock.acquire() catch unreachable);1144// await (async self.channel.put(Event{
1184 defer held.release();1145// .id = id,
11851146// .data = v,
1186 if (dir.file_table.get(basename_utf16le)) |entry| {1147// }) catch unreachable);
1187 break :blk entry.value;1148// }
1188 } else {1149// }
1189 break :blk null;1150// if (ev.NextEntryOffset == 0) break;
1190 }1151// }
1191 };1152// }
1192 if (user_value) |v| {1153// }
1193 await (async self.channel.put(Event{1154// }
1194 .id = id,1155//
1195 .data = v,1156// pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1196 }) catch unreachable);1157// @panic("TODO");
1197 }1158// }
1198 }1159//
1199 if (ev.NextEntryOffset == 0) break;1160// async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1200 }1161// const loop = channel.loop;
1201 }1162//
1202 }1163// var watch = Self{
1203 }1164// .channel = channel,
12041165// .os_data = OsData{
1205 pub async fn removeFile(self: *Self, file_path: []const u8) ?V {1166// .putter = @frame(),
1206 @panic("TODO");1167// .inotify_fd = inotify_fd,
1207 }1168// .wd_table = OsData.WdTable.init(loop.allocator),
12081169// .table_lock = event.Lock.init(loop),
1209 async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {1170// },
1210 // TODO https://github.com/ziglang/zig/issues/11941171// };
1211 suspend {1172// out_watch.* = &watch;
1212 resume @handle();1173//
1213 }1174// loop.beginOneEvent();
12141175//
1215 const loop = channel.loop;1176// defer {
12161177// watch.os_data.table_lock.deinit();
1217 var watch = Self{1178// var wd_it = watch.os_data.wd_table.iterator();
1218 .channel = channel,1179// while (wd_it.next()) |wd_entry| {
1219 .os_data = OsData{1180// var file_it = wd_entry.value.file_table.iterator();
1220 .putter = @handle(),1181// while (file_it.next()) |file_entry| {
1221 .inotify_fd = inotify_fd,1182// loop.allocator.free(file_entry.key);
1222 .wd_table = OsData.WdTable.init(loop.allocator),1183// }
1223 .table_lock = event.Lock.init(loop),1184// loop.allocator.free(wd_entry.value.dirname);
1224 },1185// }
1225 };1186// loop.finishOneEvent();
1226 out_watch.* = &watch;1187// os.close(inotify_fd);
12271188// channel.destroy();
1228 loop.beginOneEvent();1189// }
12291190//
1230 defer {1191// var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1231 watch.os_data.table_lock.deinit();1192//
1232 var wd_it = watch.os_data.wd_table.iterator();1193// while (true) {
1233 while (wd_it.next()) |wd_entry| {1194// const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1234 var file_it = wd_entry.value.file_table.iterator();1195// const errno = os.linux.getErrno(rc);
1235 while (file_it.next()) |file_entry| {1196// switch (errno) {
1236 loop.allocator.free(file_entry.key);1197// 0 => {
1237 }1198// // can't use @bytesToSlice because of the special variable length name field
1238 loop.allocator.free(wd_entry.value.dirname);1199// var ptr = event_buf[0..].ptr;
1239 }1200// const end_ptr = ptr + event_buf.len;
1240 loop.finishOneEvent();1201// var ev: *os.linux.inotify_event = undefined;
1241 os.close(inotify_fd);1202// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1242 channel.destroy();1203// ev = @ptrCast(*os.linux.inotify_event, ptr);
1243 }1204// if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
12441205// const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1245 var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;1206// const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
12461207// const user_value = blk: {
1247 while (true) {1208// const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1248 const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);1209// defer held.release();
1249 const errno = os.linux.getErrno(rc);1210//
1250 switch (errno) {1211// const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1251 0 => {1212// if (dir.file_table.get(basename_with_null)) |entry| {
1252 // can't use @bytesToSlice because of the special variable length name field1213// break :blk entry.value;
1253 var ptr = event_buf[0..].ptr;1214// } else {
1254 const end_ptr = ptr + event_buf.len;1215// break :blk null;
1255 var ev: *os.linux.inotify_event = undefined;1216// }
1256 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {1217// };
1257 ev = @ptrCast(*os.linux.inotify_event, ptr);1218// if (user_value) |v| {
1258 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {1219// await (async channel.put(Event{
1259 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);1220// .id = WatchEventId.CloseWrite,
1260 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];1221// .data = v,
1261 const user_value = blk: {1222// }) catch unreachable);
1262 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);1223// }
1263 defer held.release();1224// }
12641225// }
1265 const dir = &watch.os_data.wd_table.get(ev.wd).?.value;1226// },
1266 if (dir.file_table.get(basename_with_null)) |entry| {1227// os.linux.EINTR => continue,
1267 break :blk entry.value;1228// os.linux.EINVAL => unreachable,
1268 } else {1229// os.linux.EFAULT => unreachable,
1269 break :blk null;1230// os.linux.EAGAIN => {
1270 }1231// (await (async loop.linuxWaitFd(
1271 };1232// inotify_fd,
1272 if (user_value) |v| {1233// os.linux.EPOLLET | os.linux.EPOLLIN,
1273 await (async channel.put(Event{1234// ) catch unreachable)) catch |err| {
1274 .id = WatchEventId.CloseWrite,1235// const transformed_err = switch (err) {
1275 .data = v,1236// error.FileDescriptorAlreadyPresentInSet => unreachable,
1276 }) catch unreachable);1237// error.OperationCausesCircularLoop => unreachable,
1277 }1238// error.FileDescriptorNotRegistered => unreachable,
1278 }1239// error.FileDescriptorIncompatibleWithEpoll => unreachable,
1279 }1240// error.Unexpected => unreachable,
1280 },1241// else => |e| e,
1281 os.linux.EINTR => continue,1242// };
1282 os.linux.EINVAL => unreachable,1243// await (async channel.put(transformed_err) catch unreachable);
1283 os.linux.EFAULT => unreachable,1244// };
1284 os.linux.EAGAIN => {1245// },
1285 (await (async loop.linuxWaitFd(1246// else => unreachable,
1286 inotify_fd,1247// }
1287 os.linux.EPOLLET | os.linux.EPOLLIN,1248// }
1288 ) catch unreachable)) catch |err| {1249// }
1289 const transformed_err = switch (err) {1250// };
1290 error.FileDescriptorAlreadyPresentInSet => unreachable,1251//}
1291 error.OperationCausesCircularLoop => unreachable,
1292 error.FileDescriptorNotRegistered => unreachable,
1293 error.FileDescriptorIncompatibleWithEpoll => unreachable,
1294 error.Unexpected => unreachable,
1295 else => |e| e,
1296 };
1297 await (async channel.put(transformed_err) catch unreachable);
1298 };
1299 },
1300 else => unreachable,
1301 }
1302 }
1303 }
1304 };
1305}
13061252
1307const test_tmp_dir = "std_event_fs_test";1253const test_tmp_dir = "std_event_fs_test";
13081254
1309// TODO this test is disabled until the coroutine rewrite is finished.1255// TODO this test is disabled until the async function rewrite is finished.
1310//test "write a file, watch it, write it again" {1256//test "write a file, watch it, write it again" {
1311// return error.SkipZigTest;1257// return error.SkipZigTest;
1312// const allocator = std.heap.direct_allocator;1258// const allocator = std.heap.direct_allocator;
...@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {...@@ -1355,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void {
13551301
1356 const ev = try async watch.channel.get();1302 const ev = try async watch.channel.get();
1357 var ev_consumed = false;1303 var ev_consumed = false;
1358 defer if (!ev_consumed) cancel ev;1304 defer if (!ev_consumed) await ev;
13591305
1360 // overwrite line 21306 // overwrite line 2
1361 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);1307 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
...@@ -1397,11 +1343,11 @@ pub const OutStream = struct {...@@ -1397,11 +1343,11 @@ pub const OutStream = struct {
1397 };1343 };
1398 }1344 }
13991345
1400 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {1346 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
1401 const self = @fieldParentPtr(OutStream, "stream", out_stream);1347 const self = @fieldParentPtr(OutStream, "stream", out_stream);
1402 const offset = self.offset;1348 const offset = self.offset;
1403 self.offset += bytes.len;1349 self.offset += bytes.len;
1404 return await (async pwritev(self.loop, self.fd, [][]const u8{bytes}, offset) catch unreachable);1350 return pwritev(self.loop, self.fd, [][]const u8{bytes}, offset);
1405 }1351 }
1406};1352};
14071353
...@@ -1423,9 +1369,9 @@ pub const InStream = struct {...@@ -1423,9 +1369,9 @@ pub const InStream = struct {
1423 };1369 };
1424 }1370 }
14251371
1426 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {1372 fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
1427 const self = @fieldParentPtr(InStream, "stream", in_stream);1373 const self = @fieldParentPtr(InStream, "stream", in_stream);
1428 const amt = try await (async preadv(self.loop, self.fd, [][]u8{bytes}, self.offset) catch unreachable);1374 const amt = try preadv(self.loop, self.fd, [][]u8{bytes}, self.offset);
1429 self.offset += amt;1375 self.offset += amt;
1430 return amt;1376 return amt;
1431 }1377 }
std/event/future.zig+21-28
...@@ -2,13 +2,11 @@ const std = @import("../std.zig");...@@ -2,13 +2,11 @@ const std = @import("../std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const testing = std.testing;3const testing = std.testing;
4const builtin = @import("builtin");4const builtin = @import("builtin");
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const Lock = std.event.Lock;5const Lock = std.event.Lock;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// This is a value that starts out unavailable, until resolve() is called8/// This is a value that starts out unavailable, until resolve() is called
11/// While it is unavailable, coroutines suspend when they try to get() it,9/// While it is unavailable, functions suspend when they try to get() it,
12/// and then are resumed when resolve() is called.10/// and then are resumed when resolve() is called.
13/// At this point the value remains forever available, and another resolve() is not allowed.11/// At this point the value remains forever available, and another resolve() is not allowed.
14pub fn Future(comptime T: type) type {12pub fn Future(comptime T: type) type {
...@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {...@@ -23,7 +21,7 @@ pub fn Future(comptime T: type) type {
23 available: u8,21 available: u8,
2422
25 const Self = @This();23 const Self = @This();
26 const Queue = std.atomic.Queue(promise);24 const Queue = std.atomic.Queue(anyframe);
2725
28 pub fn init(loop: *Loop) Self {26 pub fn init(loop: *Loop) Self {
29 return Self{27 return Self{
...@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {...@@ -37,10 +35,10 @@ pub fn Future(comptime T: type) type {
37 /// available.35 /// available.
38 /// Thread-safe.36 /// Thread-safe.
39 pub async fn get(self: *Self) *T {37 pub async fn get(self: *Self) *T {
40 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {38 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
41 return &self.data;39 return &self.data;
42 }40 }
43 const held = await (async self.lock.acquire() catch unreachable);41 const held = self.lock.acquire();
44 held.release();42 held.release();
4543
46 return &self.data;44 return &self.data;
...@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {...@@ -49,7 +47,7 @@ pub fn Future(comptime T: type) type {
49 /// Gets the data without waiting for it. If it's available, a pointer is47 /// Gets the data without waiting for it. If it's available, a pointer is
50 /// returned. Otherwise, null is returned.48 /// returned. Otherwise, null is returned.
51 pub fn getOrNull(self: *Self) ?*T {49 pub fn getOrNull(self: *Self) ?*T {
52 if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) {50 if (@atomicLoad(u8, &self.available, .SeqCst) == 2) {
53 return &self.data;51 return &self.data;
54 } else {52 } else {
55 return null;53 return null;
...@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {...@@ -62,10 +60,10 @@ pub fn Future(comptime T: type) type {
62 /// It's not required to call start() before resolve() but it can be useful since60 /// It's not required to call start() before resolve() but it can be useful since
63 /// this method is thread-safe.61 /// this method is thread-safe.
64 pub async fn start(self: *Self) ?*T {62 pub async fn start(self: *Self) ?*T {
65 const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null;63 const state = @cmpxchgStrong(u8, &self.available, 0, 1, .SeqCst, .SeqCst) orelse return null;
66 switch (state) {64 switch (state) {
67 1 => {65 1 => {
68 const held = await (async self.lock.acquire() catch unreachable);66 const held = self.lock.acquire();
69 held.release();67 held.release();
70 return &self.data;68 return &self.data;
71 },69 },
...@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {...@@ -77,7 +75,7 @@ pub fn Future(comptime T: type) type {
77 /// Make the data become available. May be called only once.75 /// Make the data become available. May be called only once.
78 /// Before calling this, modify the `data` property.76 /// Before calling this, modify the `data` property.
79 pub fn resolve(self: *Self) void {77 pub fn resolve(self: *Self) void {
80 const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst);78 const prev = @atomicRmw(u8, &self.available, .Xchg, 2, .SeqCst);
81 assert(prev == 0 or prev == 1); // resolve() called twice79 assert(prev == 0 or prev == 1); // resolve() called twice
82 Lock.Held.release(Lock.Held{ .lock = &self.lock });80 Lock.Held.release(Lock.Held{ .lock = &self.lock });
83 }81 }
...@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {...@@ -86,7 +84,7 @@ pub fn Future(comptime T: type) type {
8684
87test "std.event.Future" {85test "std.event.Future" {
88 // https://github.com/ziglang/zig/issues/190886 // https://github.com/ziglang/zig/issues/1908
89 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;87 if (builtin.single_threaded) return error.SkipZigTest;
9088
91 const allocator = std.heap.direct_allocator;89 const allocator = std.heap.direct_allocator;
9290
...@@ -94,38 +92,33 @@ test "std.event.Future" {...@@ -94,38 +92,33 @@ test "std.event.Future" {
94 try loop.initMultiThreaded(allocator);92 try loop.initMultiThreaded(allocator);
95 defer loop.deinit();93 defer loop.deinit();
9694
97 const handle = try async<allocator> testFuture(&loop);95 const handle = async testFuture(&loop);
98 defer cancel handle;
9996
100 loop.run();97 loop.run();
101}98}
10299
103async fn testFuture(loop: *Loop) void {100async fn testFuture(loop: *Loop) void {
104 suspend {
105 resume @handle();
106 }
107 var future = Future(i32).init(loop);101 var future = Future(i32).init(loop);
108102
109 const a = async waitOnFuture(&future) catch @panic("memory");103 var a = async waitOnFuture(&future);
110 const b = async waitOnFuture(&future) catch @panic("memory");104 var b = async waitOnFuture(&future);
111 const c = async resolveFuture(&future) catch @panic("memory");105 var c = async resolveFuture(&future);
112106
113 const result = (await a) + (await b);107 // TODO make this work:
114 cancel c;108 //const result = (await a) + (await b);
109 const a_result = await a;
110 const b_result = await b;
111 const result = a_result + b_result;
112
113 await c;
115 testing.expect(result == 12);114 testing.expect(result == 12);
116}115}
117116
118async fn waitOnFuture(future: *Future(i32)) i32 {117async fn waitOnFuture(future: *Future(i32)) i32 {
119 suspend {118 return future.get().*;
120 resume @handle();
121 }
122 return (await (async future.get() catch @panic("memory"))).*;
123}119}
124120
125async fn resolveFuture(future: *Future(i32)) void {121async fn resolveFuture(future: *Future(i32)) void {
126 suspend {
127 resume @handle();
128 }
129 future.data = 6;122 future.data = 6;
130 future.resolve();123 future.resolve();
131}124}
std/event/group.zig+29-67
...@@ -2,46 +2,33 @@ const std = @import("../std.zig");...@@ -2,46 +2,33 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Lock = std.event.Lock;3const Lock = std.event.Lock;
4const Loop = std.event.Loop;4const Loop = std.event.Loop;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;
7const testing = std.testing;5const testing = std.testing;
86
9/// ReturnType must be `void` or `E!void`7/// ReturnType must be `void` or `E!void`
10pub fn Group(comptime ReturnType: type) type {8pub fn Group(comptime ReturnType: type) type {
11 return struct {9 return struct {
12 coro_stack: Stack,10 frame_stack: Stack,
13 alloc_stack: Stack,11 alloc_stack: Stack,
14 lock: Lock,12 lock: Lock,
1513
16 const Self = @This();14 const Self = @This();
1715
18 const Error = switch (@typeInfo(ReturnType)) {16 const Error = switch (@typeInfo(ReturnType)) {
19 builtin.TypeId.ErrorUnion => |payload| payload.error_set,17 .ErrorUnion => |payload| payload.error_set,
20 else => void,18 else => void,
21 };19 };
22 const Stack = std.atomic.Stack(promise->ReturnType);20 const Stack = std.atomic.Stack(anyframe->ReturnType);
2321
24 pub fn init(loop: *Loop) Self {22 pub fn init(loop: *Loop) Self {
25 return Self{23 return Self{
26 .coro_stack = Stack.init(),24 .frame_stack = Stack.init(),
27 .alloc_stack = Stack.init(),25 .alloc_stack = Stack.init(),
28 .lock = Lock.init(loop),26 .lock = Lock.init(loop),
29 };27 };
30 }28 }
3129
32 /// Cancel all the outstanding promises. Can be called even if wait was already called.30 /// Add a frame to the group. Thread-safe.
33 pub fn deinit(self: *Self) void {31 pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) {
34 while (self.coro_stack.pop()) |node| {
35 cancel node.data;
36 }
37 while (self.alloc_stack.pop()) |node| {
38 cancel node.data;
39 self.lock.loop.allocator.destroy(node);
40 }
41 }
42
43 /// Add a promise to the group. Thread-safe.
44 pub fn add(self: *Self, handle: promise->ReturnType) (error{OutOfMemory}!void) {
45 const node = try self.lock.loop.allocator.create(Stack.Node);32 const node = try self.lock.loop.allocator.create(Stack.Node);
46 node.* = Stack.Node{33 node.* = Stack.Node{
47 .next = undefined,34 .next = undefined,
...@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {...@@ -51,57 +38,29 @@ pub fn Group(comptime ReturnType: type) type {
51 }38 }
5239
53 /// Add a node to the group. Thread-safe. Cannot fail.40 /// Add a node to the group. Thread-safe. Cannot fail.
54 /// `node.data` should be the promise handle to add to the group.41 /// `node.data` should be the frame handle to add to the group.
55 /// The node's memory should be in the coroutine frame of42 /// The node's memory should be in the function frame of
56 /// the handle that is in the node, or somewhere guaranteed to live43 /// the handle that is in the node, or somewhere guaranteed to live
57 /// at least as long.44 /// at least as long.
58 pub fn addNode(self: *Self, node: *Stack.Node) void {45 pub fn addNode(self: *Self, node: *Stack.Node) void {
59 self.coro_stack.push(node);46 self.frame_stack.push(node);
60 }
61
62 /// This is equivalent to an async call, but the async function is added to the group, instead
63 /// of returning a promise. func must be async and have return type ReturnType.
64 /// Thread-safe.
65 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {
66 const S = struct {
67 async fn asyncFunc(node: **Stack.Node, args2: ...) ReturnType {
68 // TODO this is a hack to make the memory following be inside the coro frame
69 suspend {
70 var my_node: Stack.Node = undefined;
71 node.* = &my_node;
72 resume @handle();
73 }
74
75 // TODO this allocation elision should be guaranteed because we await it in
76 // this coro frame
77 return await (async func(args2) catch unreachable);
78 }
79 };
80 var node: *Stack.Node = undefined;
81 const handle = try async<self.lock.loop.allocator> S.asyncFunc(&node, args);
82 node.* = Stack.Node{
83 .next = undefined,
84 .data = handle,
85 };
86 self.coro_stack.push(node);
87 }47 }
8848
89 /// Wait for all the calls and promises of the group to complete.49 /// Wait for all the calls and promises of the group to complete.
90 /// Thread-safe.50 /// Thread-safe.
91 /// Safe to call any number of times.51 /// Safe to call any number of times.
92 pub async fn wait(self: *Self) ReturnType {52 pub async fn wait(self: *Self) ReturnType {
93 // TODO catch unreachable because the allocation can be grouped with53 const held = self.lock.acquire();
94 // the coro frame allocation
95 const held = await (async self.lock.acquire() catch unreachable);
96 defer held.release();54 defer held.release();
9755
98 while (self.coro_stack.pop()) |node| {56 var result: ReturnType = {};
57
58 while (self.frame_stack.pop()) |node| {
99 if (Error == void) {59 if (Error == void) {
100 await node.data;60 await node.data;
101 } else {61 } else {
102 (await node.data) catch |err| {62 (await node.data) catch |err| {
103 self.deinit();63 result = err;
104 return err;
105 };64 };
106 }65 }
107 }66 }
...@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {...@@ -112,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type {
112 await handle;71 await handle;
113 } else {72 } else {
114 (await handle) catch |err| {73 (await handle) catch |err| {
115 self.deinit();74 result = err;
116 return err;
117 };75 };
118 }76 }
119 }77 }
78 return result;
120 }79 }
121 };80 };
122}81}
...@@ -131,8 +90,7 @@ test "std.event.Group" {...@@ -131,8 +90,7 @@ test "std.event.Group" {
131 try loop.initMultiThreaded(allocator);90 try loop.initMultiThreaded(allocator);
132 defer loop.deinit();91 defer loop.deinit();
13392
134 const handle = try async<allocator> testGroup(&loop);93 const handle = async testGroup(&loop);
135 defer cancel handle;
13694
137 loop.run();95 loop.run();
138}96}
...@@ -140,26 +98,30 @@ test "std.event.Group" {...@@ -140,26 +98,30 @@ test "std.event.Group" {
140async fn testGroup(loop: *Loop) void {98async fn testGroup(loop: *Loop) void {
141 var count: usize = 0;99 var count: usize = 0;
142 var group = Group(void).init(loop);100 var group = Group(void).init(loop);
143 group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory");101 var sleep_a_little_frame = async sleepALittle(&count);
144 group.call(increaseByTen, &count) catch @panic("memory");102 group.add(&sleep_a_little_frame) catch @panic("memory");
145 await (async group.wait() catch @panic("memory"));103 var increase_by_ten_frame = async increaseByTen(&count);
104 group.add(&increase_by_ten_frame) catch @panic("memory");
105 group.wait();
146 testing.expect(count == 11);106 testing.expect(count == 11);
147107
148 var another = Group(anyerror!void).init(loop);108 var another = Group(anyerror!void).init(loop);
149 another.add(async somethingElse() catch @panic("memory")) catch @panic("memory");109 var something_else_frame = async somethingElse();
150 another.call(doSomethingThatFails) catch @panic("memory");110 another.add(&something_else_frame) catch @panic("memory");
151 testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory")));111 var something_that_fails_frame = async doSomethingThatFails();
112 another.add(&something_that_fails_frame) catch @panic("memory");
113 testing.expectError(error.ItBroke, another.wait());
152}114}
153115
154async fn sleepALittle(count: *usize) void {116async fn sleepALittle(count: *usize) void {
155 std.time.sleep(1 * std.time.millisecond);117 std.time.sleep(1 * std.time.millisecond);
156 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);118 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
157}119}
158120
159async fn increaseByTen(count: *usize) void {121async fn increaseByTen(count: *usize) void {
160 var i: usize = 0;122 var i: usize = 0;
161 while (i < 10) : (i += 1) {123 while (i < 10) : (i += 1) {
162 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);124 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
163 }125 }
164}126}
165127
std/event/io.zig+9-10
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Allocator = std.mem.Allocator;
4const assert = std.debug.assert;3const assert = std.debug.assert;
5const mem = std.mem;4const mem = std.mem;
65
...@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {...@@ -12,13 +11,13 @@ pub fn InStream(comptime ReadError: type) type {
12 /// Return the number of bytes read. It may be less than buffer.len.11 /// Return the number of bytes read. It may be less than buffer.len.
13 /// If the number of bytes read is 0, it means end of stream.12 /// If the number of bytes read is 0, it means end of stream.
14 /// End of stream is not an error condition.13 /// End of stream is not an error condition.
15 readFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!usize,14 readFn: async fn (self: *Self, buffer: []u8) Error!usize,
1615
17 /// Return the number of bytes read. It may be less than buffer.len.16 /// Return the number of bytes read. It may be less than buffer.len.
18 /// If the number of bytes read is 0, it means end of stream.17 /// If the number of bytes read is 0, it means end of stream.
19 /// End of stream is not an error condition.18 /// End of stream is not an error condition.
20 pub async fn read(self: *Self, buffer: []u8) !usize {19 pub async fn read(self: *Self, buffer: []u8) !usize {
21 return await (async self.readFn(self, buffer) catch unreachable);20 return self.readFn(self, buffer);
22 }21 }
2322
24 /// Return the number of bytes read. If it is less than buffer.len23 /// Return the number of bytes read. If it is less than buffer.len
...@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -26,7 +25,7 @@ pub fn InStream(comptime ReadError: type) type {
26 pub async fn readFull(self: *Self, buffer: []u8) !usize {25 pub async fn readFull(self: *Self, buffer: []u8) !usize {
27 var index: usize = 0;26 var index: usize = 0;
28 while (index != buf.len) {27 while (index != buf.len) {
29 const amt_read = try await (async self.read(buf[index..]) catch unreachable);28 const amt_read = try self.read(buf[index..]);
30 if (amt_read == 0) return index;29 if (amt_read == 0) return index;
31 index += amt_read;30 index += amt_read;
32 }31 }
...@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {...@@ -35,25 +34,25 @@ pub fn InStream(comptime ReadError: type) type {
3534
36 /// Same as `readFull` but end of stream returns `error.EndOfStream`.35 /// Same as `readFull` but end of stream returns `error.EndOfStream`.
37 pub async fn readNoEof(self: *Self, buf: []u8) !void {36 pub async fn readNoEof(self: *Self, buf: []u8) !void {
38 const amt_read = try await (async self.readFull(buf[index..]) catch unreachable);37 const amt_read = try self.readFull(buf[index..]);
39 if (amt_read < buf.len) return error.EndOfStream;38 if (amt_read < buf.len) return error.EndOfStream;
40 }39 }
4140
42 pub async fn readIntLittle(self: *Self, comptime T: type) !T {41 pub async fn readIntLittle(self: *Self, comptime T: type) !T {
43 var bytes: [@sizeOf(T)]u8 = undefined;42 var bytes: [@sizeOf(T)]u8 = undefined;
44 try await (async self.readNoEof(bytes[0..]) catch unreachable);43 try self.readNoEof(bytes[0..]);
45 return mem.readIntLittle(T, &bytes);44 return mem.readIntLittle(T, &bytes);
46 }45 }
4746
48 pub async fn readIntBe(self: *Self, comptime T: type) !T {47 pub async fn readIntBe(self: *Self, comptime T: type) !T {
49 var bytes: [@sizeOf(T)]u8 = undefined;48 var bytes: [@sizeOf(T)]u8 = undefined;
50 try await (async self.readNoEof(bytes[0..]) catch unreachable);49 try self.readNoEof(bytes[0..]);
51 return mem.readIntBig(T, &bytes);50 return mem.readIntBig(T, &bytes);
52 }51 }
5352
54 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {53 pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
55 var bytes: [@sizeOf(T)]u8 = undefined;54 var bytes: [@sizeOf(T)]u8 = undefined;
56 try await (async self.readNoEof(bytes[0..]) catch unreachable);55 try self.readNoEof(bytes[0..]);
57 return mem.readInt(T, &bytes, endian);56 return mem.readInt(T, &bytes, endian);
58 }57 }
5958
...@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -61,7 +60,7 @@ pub fn InStream(comptime ReadError: type) type {
61 // Only extern and packed structs have defined in-memory layout.60 // Only extern and packed structs have defined in-memory layout.
62 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);61 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
63 var res: [1]T = undefined;62 var res: [1]T = undefined;
64 try await (async self.readNoEof(@sliceToBytes(res[0..])) catch unreachable);63 try self.readNoEof(@sliceToBytes(res[0..]));
65 return res[0];64 return res[0];
66 }65 }
67 };66 };
...@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {...@@ -72,6 +71,6 @@ pub fn OutStream(comptime WriteError: type) type {
72 const Self = @This();71 const Self = @This();
73 pub const Error = WriteError;72 pub const Error = WriteError;
7473
75 writeFn: async<*Allocator> fn (self: *Self, buffer: []u8) Error!void,74 writeFn: async fn (self: *Self, buffer: []u8) Error!void,
76 };75 };
77}76}
std/event/lock.zig+24-37
...@@ -3,12 +3,10 @@ const builtin = @import("builtin");...@@ -3,12 +3,10 @@ const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// Thread-safe async/await lock.8/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and9/// Functions which are waiting for the lock are suspended, and
12/// are resumed when the lock is released, in order.10/// are resumed when the lock is released, in order.
13/// Allows only one actor to hold the lock.11/// Allows only one actor to hold the lock.
14pub const Lock = struct {12pub const Lock = struct {
...@@ -17,7 +15,7 @@ pub const Lock = struct {...@@ -17,7 +15,7 @@ pub const Lock = struct {
17 queue: Queue,15 queue: Queue,
18 queue_empty_bit: u8, // TODO make this a bool16 queue_empty_bit: u8, // TODO make this a bool
1917
20 const Queue = std.atomic.Queue(promise);18 const Queue = std.atomic.Queue(anyframe);
2119
22 pub const Held = struct {20 pub const Held = struct {
23 lock: *Lock,21 lock: *Lock,
...@@ -30,19 +28,19 @@ pub const Lock = struct {...@@ -30,19 +28,19 @@ pub const Lock = struct {
30 }28 }
3129
32 // We need to release the lock.30 // We need to release the lock.
33 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);31 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
34 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);32 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
3533
36 // There might be a queue item. If we know the queue is empty, we can be done,34 // There might be a queue item. If we know the queue is empty, we can be done,
37 // because the other actor will try to obtain the lock.35 // because the other actor will try to obtain the lock.
38 // But if there's a queue item, we are the actor which must loop and attempt36 // But if there's a queue item, we are the actor which must loop and attempt
39 // to grab the lock again.37 // to grab the lock again.
40 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {38 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
41 return;39 return;
42 }40 }
4341
44 while (true) {42 while (true) {
45 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);43 const old_bit = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 1, .SeqCst);
46 if (old_bit != 0) {44 if (old_bit != 0) {
47 // We did not obtain the lock. Great, the queue is someone else's problem.45 // We did not obtain the lock. Great, the queue is someone else's problem.
48 return;46 return;
...@@ -55,11 +53,11 @@ pub const Lock = struct {...@@ -55,11 +53,11 @@ pub const Lock = struct {
55 }53 }
5654
57 // Release the lock again.55 // Release the lock again.
58 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);56 _ = @atomicRmw(u8, &self.lock.queue_empty_bit, .Xchg, 1, .SeqCst);
59 _ = @atomicRmw(u8, &self.lock.shared_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);57 _ = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 0, .SeqCst);
6058
61 // Find out if we can be done.59 // Find out if we can be done.
62 if (@atomicLoad(u8, &self.lock.queue_empty_bit, AtomicOrder.SeqCst) == 1) {60 if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
63 return;61 return;
64 }62 }
65 }63 }
...@@ -88,28 +86,23 @@ pub const Lock = struct {...@@ -88,28 +86,23 @@ pub const Lock = struct {
88 /// All calls to acquire() and release() must complete before calling deinit().86 /// All calls to acquire() and release() must complete before calling deinit().
89 pub fn deinit(self: *Lock) void {87 pub fn deinit(self: *Lock) void {
90 assert(self.shared_bit == 0);88 assert(self.shared_bit == 0);
91 while (self.queue.get()) |node| cancel node.data;89 while (self.queue.get()) |node| resume node.data;
92 }90 }
9391
94 pub async fn acquire(self: *Lock) Held {92 pub async fn acquire(self: *Lock) Held {
95 // TODO explicitly put this memory in the coroutine frame #119493 var my_tick_node = Loop.NextTickNode.init(@frame());
96 suspend {
97 resume @handle();
98 }
99 var my_tick_node = Loop.NextTickNode.init(@handle());
10094
101 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire95 errdefer _ = self.queue.remove(&my_tick_node); // TODO test canceling an acquire
102 suspend {96 suspend {
103 self.queue.put(&my_tick_node);97 self.queue.put(&my_tick_node);
10498
105 // At this point, we are in the queue, so we might have already been resumed and this coroutine99 // At this point, we are in the queue, so we might have already been resumed.
106 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
107100
108 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor101 // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
109 // will attempt to grab the lock.102 // will attempt to grab the lock.
110 _ = @atomicRmw(u8, &self.queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);103 _ = @atomicRmw(u8, &self.queue_empty_bit, .Xchg, 0, .SeqCst);
111104
112 const old_bit = @atomicRmw(u8, &self.shared_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);105 const old_bit = @atomicRmw(u8, &self.shared_bit, .Xchg, 1, .SeqCst);
113 if (old_bit == 0) {106 if (old_bit == 0) {
114 if (self.queue.get()) |node| {107 if (self.queue.get()) |node| {
115 // Whether this node is us or someone else, we tail resume it.108 // Whether this node is us or someone else, we tail resume it.
...@@ -123,8 +116,7 @@ pub const Lock = struct {...@@ -123,8 +116,7 @@ pub const Lock = struct {
123};116};
124117
125test "std.event.Lock" {118test "std.event.Lock" {
126 // TODO https://github.com/ziglang/zig/issues/2377119 // TODO https://github.com/ziglang/zig/issues/1908
127 if (true) return error.SkipZigTest;
128 if (builtin.single_threaded) return error.SkipZigTest;120 if (builtin.single_threaded) return error.SkipZigTest;
129121
130 const allocator = std.heap.direct_allocator;122 const allocator = std.heap.direct_allocator;
...@@ -136,39 +128,34 @@ test "std.event.Lock" {...@@ -136,39 +128,34 @@ test "std.event.Lock" {
136 var lock = Lock.init(&loop);128 var lock = Lock.init(&loop);
137 defer lock.deinit();129 defer lock.deinit();
138130
139 const handle = try async<allocator> testLock(&loop, &lock);131 _ = async testLock(&loop, &lock);
140 defer cancel handle;
141 loop.run();132 loop.run();
142133
143 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);134 testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data);
144}135}
145136
146async fn testLock(loop: *Loop, lock: *Lock) void {137async fn testLock(loop: *Loop, lock: *Lock) void {
147 // TODO explicitly put next tick node memory in the coroutine frame #1194138 var handle1 = async lockRunner(lock);
148 suspend {
149 resume @handle();
150 }
151 const handle1 = async lockRunner(lock) catch @panic("out of memory");
152 var tick_node1 = Loop.NextTickNode{139 var tick_node1 = Loop.NextTickNode{
153 .prev = undefined,140 .prev = undefined,
154 .next = undefined,141 .next = undefined,
155 .data = handle1,142 .data = &handle1,
156 };143 };
157 loop.onNextTick(&tick_node1);144 loop.onNextTick(&tick_node1);
158145
159 const handle2 = async lockRunner(lock) catch @panic("out of memory");146 var handle2 = async lockRunner(lock);
160 var tick_node2 = Loop.NextTickNode{147 var tick_node2 = Loop.NextTickNode{
161 .prev = undefined,148 .prev = undefined,
162 .next = undefined,149 .next = undefined,
163 .data = handle2,150 .data = &handle2,
164 };151 };
165 loop.onNextTick(&tick_node2);152 loop.onNextTick(&tick_node2);
166153
167 const handle3 = async lockRunner(lock) catch @panic("out of memory");154 var handle3 = async lockRunner(lock);
168 var tick_node3 = Loop.NextTickNode{155 var tick_node3 = Loop.NextTickNode{
169 .prev = undefined,156 .prev = undefined,
170 .next = undefined,157 .next = undefined,
171 .data = handle3,158 .data = &handle3,
172 };159 };
173 loop.onNextTick(&tick_node3);160 loop.onNextTick(&tick_node3);
174161
...@@ -185,8 +172,8 @@ async fn lockRunner(lock: *Lock) void {...@@ -185,8 +172,8 @@ async fn lockRunner(lock: *Lock) void {
185172
186 var i: usize = 0;173 var i: usize = 0;
187 while (i < shared_test_data.len) : (i += 1) {174 while (i < shared_test_data.len) : (i += 1) {
188 const lock_promise = async lock.acquire() catch @panic("out of memory");175 var lock_frame = async lock.acquire();
189 const handle = await lock_promise;176 const handle = await lock_frame;
190 defer handle.release();177 defer handle.release();
191178
192 shared_test_index = 0;179 shared_test_index = 0;
std/event/locked.zig+1-1
...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;...@@ -3,7 +3,7 @@ const Lock = std.event.Lock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await lock that protects one piece of data.5/// Thread-safe async/await lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and6/// Functions which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn Locked(comptime T: type) type {8pub fn Locked(comptime T: type) type {
9 return struct {9 return struct {
std/event/loop.zig+82-69
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const root = @import("root");
3const assert = std.debug.assert;4const assert = std.debug.assert;
4const testing = std.testing;5const testing = std.testing;
5const mem = std.mem;6const mem = std.mem;
...@@ -13,7 +14,7 @@ const Thread = std.Thread;...@@ -13,7 +14,7 @@ const Thread = std.Thread;
1314
14pub const Loop = struct {15pub const Loop = struct {
15 allocator: *mem.Allocator,16 allocator: *mem.Allocator,
16 next_tick_queue: std.atomic.Queue(promise),17 next_tick_queue: std.atomic.Queue(anyframe),
17 os_data: OsData,18 os_data: OsData,
18 final_resume_node: ResumeNode,19 final_resume_node: ResumeNode,
19 pending_event_count: usize,20 pending_event_count: usize,
...@@ -24,11 +25,11 @@ pub const Loop = struct {...@@ -24,11 +25,11 @@ pub const Loop = struct {
24 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),25 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
25 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,26 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,
2627
27 pub const NextTickNode = std.atomic.Queue(promise).Node;28 pub const NextTickNode = std.atomic.Queue(anyframe).Node;
2829
29 pub const ResumeNode = struct {30 pub const ResumeNode = struct {
30 id: Id,31 id: Id,
31 handle: promise,32 handle: anyframe,
32 overlapped: Overlapped,33 overlapped: Overlapped,
3334
34 pub const overlapped_init = switch (builtin.os) {35 pub const overlapped_init = switch (builtin.os) {
...@@ -85,18 +86,43 @@ pub const Loop = struct {...@@ -85,18 +86,43 @@ pub const Loop = struct {
85 };86 };
86 };87 };
8788
89 pub const IoMode = enum {
90 blocking,
91 evented,
92 };
93 pub const io_mode: IoMode = if (@hasDecl(root, "io_mode")) root.io_mode else IoMode.blocking;
94 var global_instance_state: Loop = undefined;
95 const default_instance: ?*Loop = switch (io_mode) {
96 .blocking => null,
97 .evented => &global_instance_state,
98 };
99 pub const instance: ?*Loop = if (@hasDecl(root, "event_loop")) root.event_loop else default_instance;
100
101 /// TODO copy elision / named return values so that the threads referencing *Loop
102 /// have the correct pointer value.
103 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
104 pub fn init(self: *Loop, allocator: *mem.Allocator) !void {
105 if (builtin.single_threaded) {
106 return self.initSingleThreaded(allocator);
107 } else {
108 return self.initMultiThreaded(allocator);
109 }
110 }
111
88 /// After initialization, call run().112 /// After initialization, call run().
89 /// TODO copy elision / named return values so that the threads referencing *Loop113 /// TODO copy elision / named return values so that the threads referencing *Loop
90 /// have the correct pointer value.114 /// have the correct pointer value.
115 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
91 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {116 pub fn initSingleThreaded(self: *Loop, allocator: *mem.Allocator) !void {
92 return self.initInternal(allocator, 1);117 return self.initInternal(allocator, 1);
93 }118 }
94119
95 /// The allocator must be thread-safe because we use it for multiplexing120 /// The allocator must be thread-safe because we use it for multiplexing
96 /// coroutines onto kernel threads.121 /// async functions onto kernel threads.
97 /// After initialization, call run().122 /// After initialization, call run().
98 /// TODO copy elision / named return values so that the threads referencing *Loop123 /// TODO copy elision / named return values so that the threads referencing *Loop
99 /// have the correct pointer value.124 /// have the correct pointer value.
125 /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765
100 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {126 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
101 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");127 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
102 const core_count = try Thread.cpuCount();128 const core_count = try Thread.cpuCount();
...@@ -110,7 +136,7 @@ pub const Loop = struct {...@@ -110,7 +136,7 @@ pub const Loop = struct {
110 .pending_event_count = 1,136 .pending_event_count = 1,
111 .allocator = allocator,137 .allocator = allocator,
112 .os_data = undefined,138 .os_data = undefined,
113 .next_tick_queue = std.atomic.Queue(promise).init(),139 .next_tick_queue = std.atomic.Queue(anyframe).init(),
114 .extra_threads = undefined,140 .extra_threads = undefined,
115 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),141 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
116 .eventfd_resume_nodes = undefined,142 .eventfd_resume_nodes = undefined,
...@@ -397,7 +423,7 @@ pub const Loop = struct {...@@ -397,7 +423,7 @@ pub const Loop = struct {
397 }423 }
398 }424 }
399425
400 /// resume_node must live longer than the promise that it holds a reference to.426 /// resume_node must live longer than the anyframe that it holds a reference to.
401 /// flags must contain EPOLLET427 /// flags must contain EPOLLET
402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {428 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403 assert(flags & os.EPOLLET == os.EPOLLET);429 assert(flags & os.EPOLLET == os.EPOLLET);
...@@ -428,11 +454,10 @@ pub const Loop = struct {...@@ -428,11 +454,10 @@ pub const Loop = struct {
428 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {454 pub async fn linuxWaitFd(self: *Loop, fd: i32, flags: u32) !void {
429 defer self.linuxRemoveFd(fd);455 defer self.linuxRemoveFd(fd);
430 suspend {456 suspend {
431 // TODO explicitly put this memory in the coroutine frame #1194
432 var resume_node = ResumeNode.Basic{457 var resume_node = ResumeNode.Basic{
433 .base = ResumeNode{458 .base = ResumeNode{
434 .id = ResumeNode.Id.Basic,459 .id = ResumeNode.Id.Basic,
435 .handle = @handle(),460 .handle = @frame(),
436 .overlapped = ResumeNode.overlapped_init,461 .overlapped = ResumeNode.overlapped_init,
437 },462 },
438 };463 };
...@@ -441,14 +466,10 @@ pub const Loop = struct {...@@ -441,14 +466,10 @@ pub const Loop = struct {
441 }466 }
442467
443 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {468 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
444 // TODO #1194
445 suspend {
446 resume @handle();
447 }
448 var resume_node = ResumeNode.Basic{469 var resume_node = ResumeNode.Basic{
449 .base = ResumeNode{470 .base = ResumeNode{
450 .id = ResumeNode.Id.Basic,471 .id = ResumeNode.Id.Basic,
451 .handle = @handle(),472 .handle = @frame(),
452 .overlapped = ResumeNode.overlapped_init,473 .overlapped = ResumeNode.overlapped_init,
453 },474 },
454 .kev = undefined,475 .kev = undefined,
...@@ -460,7 +481,7 @@ pub const Loop = struct {...@@ -460,7 +481,7 @@ pub const Loop = struct {
460 return resume_node.kev;481 return resume_node.kev;
461 }482 }
462483
463 /// resume_node must live longer than the promise that it holds a reference to.484 /// resume_node must live longer than the anyframe that it holds a reference to.
464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {485 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465 self.beginOneEvent();486 self.beginOneEvent();
466 errdefer self.finishOneEvent();487 errdefer self.finishOneEvent();
...@@ -561,10 +582,10 @@ pub const Loop = struct {...@@ -561,10 +582,10 @@ pub const Loop = struct {
561 self.workerRun();582 self.workerRun();
562583
563 switch (builtin.os) {584 switch (builtin.os) {
564 builtin.Os.linux,585 .linux,
565 builtin.Os.macosx,586 .macosx,
566 builtin.Os.freebsd,587 .freebsd,
567 builtin.Os.netbsd,588 .netbsd,
568 => self.os_data.fs_thread.wait(),589 => self.os_data.fs_thread.wait(),
569 else => {},590 else => {},
570 }591 }
...@@ -574,45 +595,38 @@ pub const Loop = struct {...@@ -574,45 +595,38 @@ pub const Loop = struct {
574 }595 }
575 }596 }
576597
577 /// This is equivalent to an async call, except instead of beginning execution of the async function,598 /// This is equivalent to function call, except it calls `startCpuBoundOperation` first.
578 /// it immediately returns to the caller, and the async function is queued in the event loop. It still599 pub fn call(comptime func: var, args: ...) @typeOf(func).ReturnType {
579 /// returns a promise to be awaited.600 startCpuBoundOperation();
580 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {601 return func(args);
581 const S = struct {
582 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
583 suspend {
584 handle.* = @handle();
585 var my_tick_node = Loop.NextTickNode{
586 .prev = undefined,
587 .next = undefined,
588 .data = @handle(),
589 };
590 loop.onNextTick(&my_tick_node);
591 }
592 // TODO guaranteed allocation elision for await in same func as async
593 return await (async func(args2) catch unreachable);
594 }
595 };
596 var handle: promise->@typeOf(func).ReturnType = undefined;
597 return async<self.allocator> S.asyncFunc(self, &handle, args);
598 }602 }
599603
600 /// Awaiting a yield lets the event loop run, starting any unstarted async operations.604 /// Yielding lets the event loop run, starting any unstarted async operations.
601 /// Note that async operations automatically start when a function yields for any other reason,605 /// Note that async operations automatically start when a function yields for any other reason,
602 /// for example, when async I/O is performed. This function is intended to be used only when606 /// for example, when async I/O is performed. This function is intended to be used only when
603 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O607 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
604 /// is performed.608 /// is performed.
605 pub async fn yield(self: *Loop) void {609 pub fn yield(self: *Loop) void {
606 suspend {610 suspend {
607 var my_tick_node = Loop.NextTickNode{611 var my_tick_node = NextTickNode{
608 .prev = undefined,612 .prev = undefined,
609 .next = undefined,613 .next = undefined,
610 .data = @handle(),614 .data = @frame(),
611 };615 };
612 self.onNextTick(&my_tick_node);616 self.onNextTick(&my_tick_node);
613 }617 }
614 }618 }
615619
620 /// If the build is multi-threaded and there is an event loop, then it calls `yield`. Otherwise,
621 /// does nothing.
622 pub fn startCpuBoundOperation() void {
623 if (builtin.single_threaded) {
624 return;
625 } else if (instance) |event_loop| {
626 event_loop.yield();
627 }
628 }
629
616 /// call finishOneEvent when done630 /// call finishOneEvent when done
617 pub fn beginOneEvent(self: *Loop) void {631 pub fn beginOneEvent(self: *Loop) void {
618 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);632 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
...@@ -672,9 +686,9 @@ pub const Loop = struct {...@@ -672,9 +686,9 @@ pub const Loop = struct {
672 const handle = resume_node.handle;686 const handle = resume_node.handle;
673 const resume_node_id = resume_node.id;687 const resume_node_id = resume_node.id;
674 switch (resume_node_id) {688 switch (resume_node_id) {
675 ResumeNode.Id.Basic => {},689 .Basic => {},
676 ResumeNode.Id.Stop => return,690 .Stop => return,
677 ResumeNode.Id.EventFd => {691 .EventFd => {
678 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);692 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;693 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);694 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
...@@ -696,12 +710,12 @@ pub const Loop = struct {...@@ -696,12 +710,12 @@ pub const Loop = struct {
696 const handle = resume_node.handle;710 const handle = resume_node.handle;
697 const resume_node_id = resume_node.id;711 const resume_node_id = resume_node.id;
698 switch (resume_node_id) {712 switch (resume_node_id) {
699 ResumeNode.Id.Basic => {713 .Basic => {
700 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);714 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);
701 basic_node.kev = ev;715 basic_node.kev = ev;
702 },716 },
703 ResumeNode.Id.Stop => return,717 .Stop => return,
704 ResumeNode.Id.EventFd => {718 .EventFd => {
705 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);719 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
706 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);720 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
707 self.available_eventfd_resume_nodes.push(stack_node);721 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -730,9 +744,9 @@ pub const Loop = struct {...@@ -730,9 +744,9 @@ pub const Loop = struct {
730 const handle = resume_node.handle;744 const handle = resume_node.handle;
731 const resume_node_id = resume_node.id;745 const resume_node_id = resume_node.id;
732 switch (resume_node_id) {746 switch (resume_node_id) {
733 ResumeNode.Id.Basic => {},747 .Basic => {},
734 ResumeNode.Id.Stop => return,748 .Stop => return,
735 ResumeNode.Id.EventFd => {749 .EventFd => {
736 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);750 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
737 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);751 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
738 self.available_eventfd_resume_nodes.push(stack_node);752 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -750,12 +764,12 @@ pub const Loop = struct {...@@ -750,12 +764,12 @@ pub const Loop = struct {
750 self.beginOneEvent(); // finished in posixFsRun after processing the msg764 self.beginOneEvent(); // finished in posixFsRun after processing the msg
751 self.os_data.fs_queue.put(request_node);765 self.os_data.fs_queue.put(request_node);
752 switch (builtin.os) {766 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {767 .macosx, .freebsd, .netbsd => {
754 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);768 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];769 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;770 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757 },771 },
758 builtin.Os.linux => {772 .linux => {
759 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);773 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);774 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761 switch (os.linux.getErrno(rc)) {775 switch (os.linux.getErrno(rc)) {
...@@ -781,18 +795,18 @@ pub const Loop = struct {...@@ -781,18 +795,18 @@ pub const Loop = struct {
781 }795 }
782 while (self.os_data.fs_queue.get()) |node| {796 while (self.os_data.fs_queue.get()) |node| {
783 switch (node.data.msg) {797 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,798 .End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {799 .PWriteV => |*msg| {
786 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);800 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787 },801 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {802 .PReadV => |*msg| {
789 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);803 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790 },804 },
791 @TagType(fs.Request.Msg).Open => |*msg| {805 .Open => |*msg| {
792 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);806 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793 },807 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),808 .Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {809 .WriteFile => |*msg| blk: {
796 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |810 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797 os.O_CLOEXEC | os.O_TRUNC;811 os.O_CLOEXEC | os.O_TRUNC;
798 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {812 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
...@@ -804,11 +818,11 @@ pub const Loop = struct {...@@ -804,11 +818,11 @@ pub const Loop = struct {
804 },818 },
805 }819 }
806 switch (node.data.finish) {820 switch (node.data.finish) {
807 @TagType(fs.Request.Finish).TickNode => |*tick_node| self.onNextTick(tick_node),821 .TickNode => |*tick_node| self.onNextTick(tick_node),
808 @TagType(fs.Request.Finish).DeallocCloseOperation => |close_op| {822 .DeallocCloseOperation => |close_op| {
809 self.allocator.destroy(close_op);823 self.allocator.destroy(close_op);
810 },824 },
811 @TagType(fs.Request.Finish).NoAction => {},825 .NoAction => {},
812 }826 }
813 self.finishOneEvent();827 self.finishOneEvent();
814 }828 }
...@@ -864,7 +878,7 @@ pub const Loop = struct {...@@ -864,7 +878,7 @@ pub const Loop = struct {
864878
865test "std.event.Loop - basic" {879test "std.event.Loop - basic" {
866 // https://github.com/ziglang/zig/issues/1908880 // 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
869 const allocator = std.heap.direct_allocator;883 const allocator = std.heap.direct_allocator;
870884
...@@ -877,7 +891,7 @@ test "std.event.Loop - basic" {...@@ -877,7 +891,7 @@ test "std.event.Loop - basic" {
877891
878test "std.event.Loop - call" {892test "std.event.Loop - call" {
879 // https://github.com/ziglang/zig/issues/1908893 // 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
882 const allocator = std.heap.direct_allocator;896 const allocator = std.heap.direct_allocator;
883897
...@@ -886,9 +900,8 @@ test "std.event.Loop - call" {...@@ -886,9 +900,8 @@ test "std.event.Loop - call" {
886 defer loop.deinit();900 defer loop.deinit();
887901
888 var did_it = false;902 var did_it = false;
889 const handle = try loop.call(testEventLoop);903 var handle = async Loop.call(testEventLoop);
890 const handle2 = try loop.call(testEventLoop2, handle, &did_it);904 var handle2 = async Loop.call(testEventLoop2, &handle, &did_it);
891 defer cancel handle2;
892905
893 loop.run();906 loop.run();
894907
...@@ -899,7 +912,7 @@ async fn testEventLoop() i32 {...@@ -899,7 +912,7 @@ async fn testEventLoop() i32 {
899 return 1234;912 return 1234;
900}913}
901914
902async fn testEventLoop2(h: promise->i32, did_it: *bool) void {915async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
903 const value = await h;916 const value = await h;
904 testing.expect(value == 1234);917 testing.expect(value == 1234);
905 did_it.* = true;918 did_it.* = true;
std/event/net.zig+27-38
...@@ -9,24 +9,24 @@ const File = std.fs.File;...@@ -9,24 +9,24 @@ const File = std.fs.File;
9const fd_t = os.fd_t;9const fd_t = os.fd_t;
1010
11pub const Server = struct {11pub const Server = struct {
12 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,12 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
1313
14 loop: *Loop,14 loop: *Loop,
15 sockfd: ?i32,15 sockfd: ?i32,
16 accept_coro: ?promise,16 accept_frame: ?anyframe,
17 listen_address: std.net.Address,17 listen_address: std.net.Address,
1818
19 waiting_for_emfile_node: PromiseNode,19 waiting_for_emfile_node: PromiseNode,
20 listen_resume_node: event.Loop.ResumeNode,20 listen_resume_node: event.Loop.ResumeNode,
2121
22 const PromiseNode = std.TailQueue(promise).Node;22 const PromiseNode = std.TailQueue(anyframe).Node;
2323
24 pub fn init(loop: *Loop) Server {24 pub fn init(loop: *Loop) Server {
25 // TODO can't initialize handler coroutine here because we need well defined copy elision25 // TODO can't initialize handler here because we need well defined copy elision
26 return Server{26 return Server{
27 .loop = loop,27 .loop = loop,
28 .sockfd = null,28 .sockfd = null,
29 .accept_coro = null,29 .accept_frame = null,
30 .handleRequestFn = undefined,30 .handleRequestFn = undefined,
31 .waiting_for_emfile_node = undefined,31 .waiting_for_emfile_node = undefined,
32 .listen_address = undefined,32 .listen_address = undefined,
...@@ -41,7 +41,7 @@ pub const Server = struct {...@@ -41,7 +41,7 @@ pub const Server = struct {
41 pub fn listen(41 pub fn listen(
42 self: *Server,42 self: *Server,
43 address: *const std.net.Address,43 address: *const std.net.Address,
44 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,44 handleRequestFn: async fn (*Server, *const std.net.Address, File) void,
45 ) !void {45 ) !void {
46 self.handleRequestFn = handleRequestFn;46 self.handleRequestFn = handleRequestFn;
4747
...@@ -53,10 +53,10 @@ pub const Server = struct {...@@ -53,10 +53,10 @@ pub const Server = struct {
53 try os.listen(sockfd, os.SOMAXCONN);53 try os.listen(sockfd, os.SOMAXCONN);
54 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));54 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
5555
56 self.accept_coro = try async<self.loop.allocator> Server.handler(self);56 self.accept_frame = async Server.handler(self);
57 errdefer cancel self.accept_coro.?;57 errdefer await self.accept_frame.?;
5858
59 self.listen_resume_node.handle = self.accept_coro.?;59 self.listen_resume_node.handle = self.accept_frame.?;
60 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);60 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
61 errdefer self.loop.removeFd(sockfd);61 errdefer self.loop.removeFd(sockfd);
62 }62 }
...@@ -71,7 +71,7 @@ pub const Server = struct {...@@ -71,7 +71,7 @@ pub const Server = struct {
71 }71 }
7272
73 pub fn deinit(self: *Server) void {73 pub fn deinit(self: *Server) void {
74 if (self.accept_coro) |accept_coro| cancel accept_coro;74 if (self.accept_frame) |accept_frame| await accept_frame;
75 if (self.sockfd) |sockfd| os.close(sockfd);75 if (self.sockfd) |sockfd| os.close(sockfd);
76 }76 }
7777
...@@ -86,12 +86,7 @@ pub const Server = struct {...@@ -86,12 +86,7 @@ pub const Server = struct {
86 continue;86 continue;
87 }87 }
88 var socket = File.openHandle(accepted_fd);88 var socket = File.openHandle(accepted_fd);
89 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {89 self.handleRequestFn(self, &accepted_addr, socket);
90 error.OutOfMemory => {
91 socket.close();
92 continue;
93 },
94 };
95 } else |err| switch (err) {90 } else |err| switch (err) {
96 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),91 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
97 error.ConnectionAborted => continue,92 error.ConnectionAborted => continue,
...@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {...@@ -124,7 +119,7 @@ pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
124 mem.copy(u8, sock_addr.path[0..], path);119 mem.copy(u8, sock_addr.path[0..], path);
125 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);120 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
126 try os.connect_async(sockfd, &sock_addr, size);121 try os.connect_async(sockfd, &sock_addr, size);
127 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);122 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
128 try os.getsockoptError(sockfd);123 try os.getsockoptError(sockfd);
129124
130 return sockfd;125 return sockfd;
...@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize...@@ -149,7 +144,7 @@ pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize
149 .iov_len = buffer.len,144 .iov_len = buffer.len,
150 };145 };
151 const iovs: *const [1]os.iovec = &iov;146 const iovs: *const [1]os.iovec = &iov;
152 return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);147 return readvPosix(loop, fd, iovs, 1);
153}148}
154149
155pub const WriteError = error{};150pub const WriteError = error{};
...@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr...@@ -160,7 +155,7 @@ pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteErr
160 .iov_len = buffer.len,155 .iov_len = buffer.len,
161 };156 };
162 const iovs: *const [1]os.iovec_const = &iov;157 const iovs: *const [1]os.iovec_const = &iov;
163 return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);158 return writevPosix(loop, fd, iovs, 1);
164}159}
165160
166pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {161pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
...@@ -174,7 +169,7 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, cou...@@ -174,7 +169,7 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, cou
174 os.EINVAL => unreachable,169 os.EINVAL => unreachable,
175 os.EFAULT => unreachable,170 os.EFAULT => unreachable,
176 os.EAGAIN => {171 os.EAGAIN => {
177 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);172 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT);
178 continue;173 continue;
179 },174 },
180 os.EBADF => unreachable, // always a race condition175 os.EBADF => unreachable, // always a race condition
...@@ -205,7 +200,7 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count:...@@ -205,7 +200,7 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count:
205 os.EINVAL => unreachable,200 os.EINVAL => unreachable,
206 os.EFAULT => unreachable,201 os.EFAULT => unreachable,
207 os.EAGAIN => {202 os.EAGAIN => {
208 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);203 try loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN);
209 continue;204 continue;
210 },205 },
211 os.EBADF => unreachable, // always a race condition206 os.EBADF => unreachable, // always a race condition
...@@ -232,7 +227,7 @@ pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {...@@ -232,7 +227,7 @@ pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
232 };227 };
233 }228 }
234229
235 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);230 return writevPosix(loop, fd, iovecs.ptr, data.len);
236}231}
237232
238pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {233pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
...@@ -246,7 +241,7 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {...@@ -246,7 +241,7 @@ pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
246 };241 };
247 }242 }
248243
249 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);244 return readvPosix(loop, fd, iovecs.ptr, data.len);
250}245}
251246
252pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {247pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
...@@ -256,7 +251,7 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {...@@ -256,7 +251,7 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
256 errdefer os.close(sockfd);251 errdefer os.close(sockfd);
257252
258 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));253 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
259 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);254 try loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
260 try os.getsockoptError(sockfd);255 try os.getsockoptError(sockfd);
261256
262 return File.openHandle(sockfd);257 return File.openHandle(sockfd);
...@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {...@@ -275,18 +270,13 @@ test "listen on a port, send bytes, receive bytes" {
275 tcp_server: Server,270 tcp_server: Server,
276271
277 const Self = @This();272 const Self = @This();
278 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {273 async fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
279 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);274 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
280 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592275 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
281 defer socket.close();276 defer socket.close();
282 // TODO guarantee elision of this allocation277 const next_handler = errorableHandler(self, _addr, socket) catch |err| {
283 const next_handler = async errorableHandler(self, _addr, socket) catch unreachable;
284 (await next_handler) catch |err| {
285 std.debug.panic("unable to handle connection: {}\n", err);278 std.debug.panic("unable to handle connection: {}\n", err);
286 };279 };
287 suspend {
288 cancel @handle();
289 }
290 }280 }
291 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {281 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
292 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592282 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
...@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {...@@ -306,15 +296,14 @@ test "listen on a port, send bytes, receive bytes" {
306 defer server.tcp_server.deinit();296 defer server.tcp_server.deinit();
307 try server.tcp_server.listen(&addr, MyServer.handler);297 try server.tcp_server.listen(&addr, MyServer.handler);
308298
309 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);299 _ = async doAsyncTest(&loop, &server.tcp_server.listen_address, &server.tcp_server);
310 defer cancel p;
311 loop.run();300 loop.run();
312}301}
313302
314async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {303async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Server) void {
315 errdefer @panic("test failure");304 errdefer @panic("test failure");
316305
317 var socket_file = try await try async connect(loop, address);306 var socket_file = try connect(loop, address);
318 defer socket_file.close();307 defer socket_file.close();
319308
320 var buf: [512]u8 = undefined;309 var buf: [512]u8 = undefined;
...@@ -340,9 +329,9 @@ pub const OutStream = struct {...@@ -340,9 +329,9 @@ pub const OutStream = struct {
340 };329 };
341 }330 }
342331
343 async<*mem.Allocator> fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {332 async fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
344 const self = @fieldParentPtr(OutStream, "stream", out_stream);333 const self = @fieldParentPtr(OutStream, "stream", out_stream);
345 return await (async write(self.loop, self.fd, bytes) catch unreachable);334 return write(self.loop, self.fd, bytes);
346 }335 }
347};336};
348337
...@@ -362,8 +351,8 @@ pub const InStream = struct {...@@ -362,8 +351,8 @@ pub const InStream = struct {
362 };351 };
363 }352 }
364353
365 async<*mem.Allocator> fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {354 async fn readFn(in_stream: *Stream, bytes: []u8) Error!usize {
366 const self = @fieldParentPtr(InStream, "stream", in_stream);355 const self = @fieldParentPtr(InStream, "stream", in_stream);
367 return await (async read(self.loop, self.fd, bytes) catch unreachable);356 return read(self.loop, self.fd, bytes);
368 }357 }
369};358};
std/event/rwlock.zig+46-47
...@@ -3,12 +3,10 @@ const builtin = @import("builtin");...@@ -3,12 +3,10 @@ const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;
8const Loop = std.event.Loop;6const Loop = std.event.Loop;
97
10/// Thread-safe async/await lock.8/// Thread-safe async/await lock.
11/// coroutines which are waiting for the lock are suspended, and9/// Functions which are waiting for the lock are suspended, and
12/// are resumed when the lock is released, in order.10/// are resumed when the lock is released, in order.
13/// Many readers can hold the lock at the same time; however locking for writing is exclusive.11/// Many readers can hold the lock at the same time; however locking for writing is exclusive.
14/// When a read lock is held, it will not be released until the reader queue is empty.12/// When a read lock is held, it will not be released until the reader queue is empty.
...@@ -28,19 +26,19 @@ pub const RwLock = struct {...@@ -28,19 +26,19 @@ pub const RwLock = struct {
28 const ReadLock = 2;26 const ReadLock = 2;
29 };27 };
3028
31 const Queue = std.atomic.Queue(promise);29 const Queue = std.atomic.Queue(anyframe);
3230
33 pub const HeldRead = struct {31 pub const HeldRead = struct {
34 lock: *RwLock,32 lock: *RwLock,
3533
36 pub fn release(self: HeldRead) void {34 pub fn release(self: HeldRead) void {
37 // If other readers still hold the lock, we're done.35 // If other readers still hold the lock, we're done.
38 if (@atomicRmw(usize, &self.lock.reader_lock_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst) != 1) {36 if (@atomicRmw(usize, &self.lock.reader_lock_count, .Sub, 1, .SeqCst) != 1) {
39 return;37 return;
40 }38 }
4139
42 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);40 _ = @atomicRmw(u8, &self.lock.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
43 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {41 if (@cmpxchgStrong(u8, &self.lock.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
44 // Didn't unlock. Someone else's problem.42 // Didn't unlock. Someone else's problem.
45 return;43 return;
46 }44 }
...@@ -61,17 +59,17 @@ pub const RwLock = struct {...@@ -61,17 +59,17 @@ pub const RwLock = struct {
61 }59 }
6260
63 // We need to release the write lock. Check if any readers are waiting to grab the lock.61 // We need to release the write lock. Check if any readers are waiting to grab the lock.
64 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {62 if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, .SeqCst) == 0) {
65 // Switch to a read lock.63 // Switch to a read lock.
66 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.ReadLock, AtomicOrder.SeqCst);64 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.ReadLock, .SeqCst);
67 while (self.lock.reader_queue.get()) |node| {65 while (self.lock.reader_queue.get()) |node| {
68 self.lock.loop.onNextTick(node);66 self.lock.loop.onNextTick(node);
69 }67 }
70 return;68 return;
71 }69 }
7270
73 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);71 _ = @atomicRmw(u8, &self.lock.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
74 _ = @atomicRmw(u8, &self.lock.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);72 _ = @atomicRmw(u8, &self.lock.shared_state, .Xchg, State.Unlocked, .SeqCst);
7573
76 self.lock.commonPostUnlock();74 self.lock.commonPostUnlock();
77 }75 }
...@@ -93,32 +91,30 @@ pub const RwLock = struct {...@@ -93,32 +91,30 @@ pub const RwLock = struct {
93 /// All calls to acquire() and release() must complete before calling deinit().91 /// All calls to acquire() and release() must complete before calling deinit().
94 pub fn deinit(self: *RwLock) void {92 pub fn deinit(self: *RwLock) void {
95 assert(self.shared_state == State.Unlocked);93 assert(self.shared_state == State.Unlocked);
96 while (self.writer_queue.get()) |node| cancel node.data;94 while (self.writer_queue.get()) |node| resume node.data;
97 while (self.reader_queue.get()) |node| cancel node.data;95 while (self.reader_queue.get()) |node| resume node.data;
98 }96 }
9997
100 pub async fn acquireRead(self: *RwLock) HeldRead {98 pub async fn acquireRead(self: *RwLock) HeldRead {
101 _ = @atomicRmw(usize, &self.reader_lock_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);99 _ = @atomicRmw(usize, &self.reader_lock_count, .Add, 1, .SeqCst);
102100
103 suspend {101 suspend {
104 // TODO explicitly put this memory in the coroutine frame #1194
105 var my_tick_node = Loop.NextTickNode{102 var my_tick_node = Loop.NextTickNode{
106 .data = @handle(),103 .data = @frame(),
107 .prev = undefined,104 .prev = undefined,
108 .next = undefined,105 .next = undefined,
109 };106 };
110107
111 self.reader_queue.put(&my_tick_node);108 self.reader_queue.put(&my_tick_node);
112109
113 // At this point, we are in the reader_queue, so we might have already been resumed and this coroutine110 // At this point, we are in the reader_queue, so we might have already been resumed.
114 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
115111
116 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,112 // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
117 // some actor will attempt to grab the lock.113 // some actor will attempt to grab the lock.
118 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);114 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 0, .SeqCst);
119115
120 // Here we don't care if we are the one to do the locking or if it was already locked for reading.116 // Here we don't care if we are the one to do the locking or if it was already locked for reading.
121 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |old_state| old_state == State.ReadLock else true;117 const have_read_lock = if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst)) |old_state| old_state == State.ReadLock else true;
122 if (have_read_lock) {118 if (have_read_lock) {
123 // Give out all the read locks.119 // Give out all the read locks.
124 if (self.reader_queue.get()) |first_node| {120 if (self.reader_queue.get()) |first_node| {
...@@ -134,24 +130,22 @@ pub const RwLock = struct {...@@ -134,24 +130,22 @@ pub const RwLock = struct {
134130
135 pub async fn acquireWrite(self: *RwLock) HeldWrite {131 pub async fn acquireWrite(self: *RwLock) HeldWrite {
136 suspend {132 suspend {
137 // TODO explicitly put this memory in the coroutine frame #1194
138 var my_tick_node = Loop.NextTickNode{133 var my_tick_node = Loop.NextTickNode{
139 .data = @handle(),134 .data = @frame(),
140 .prev = undefined,135 .prev = undefined,
141 .next = undefined,136 .next = undefined,
142 };137 };
143138
144 self.writer_queue.put(&my_tick_node);139 self.writer_queue.put(&my_tick_node);
145140
146 // At this point, we are in the writer_queue, so we might have already been resumed and this coroutine141 // At this point, we are in the writer_queue, so we might have already been resumed.
147 // frame might be destroyed. For the rest of the suspend block we cannot access the coroutine frame.
148142
149 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,143 // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
150 // some actor will attempt to grab the lock.144 // some actor will attempt to grab the lock.
151 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);145 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 0, .SeqCst);
152146
153 // Here we must be the one to acquire the write lock. It cannot already be locked.147 // Here we must be the one to acquire the write lock. It cannot already be locked.
154 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null) {148 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) == null) {
155 // We now have a write lock.149 // We now have a write lock.
156 if (self.writer_queue.get()) |node| {150 if (self.writer_queue.get()) |node| {
157 // Whether this node is us or someone else, we tail resume it.151 // Whether this node is us or someone else, we tail resume it.
...@@ -169,8 +163,8 @@ pub const RwLock = struct {...@@ -169,8 +163,8 @@ pub const RwLock = struct {
169 // obtain the lock.163 // obtain the lock.
170 // But if there's a writer_queue item or a reader_queue item,164 // But if there's a writer_queue item or a reader_queue item,
171 // we are the actor which must loop and attempt to grab the lock again.165 // we are the actor which must loop and attempt to grab the lock again.
172 if (@atomicLoad(u8, &self.writer_queue_empty_bit, AtomicOrder.SeqCst) == 0) {166 if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
173 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {167 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.WriteLock, .SeqCst, .SeqCst) != null) {
174 // We did not obtain the lock. Great, the queues are someone else's problem.168 // We did not obtain the lock. Great, the queues are someone else's problem.
175 return;169 return;
176 }170 }
...@@ -180,13 +174,13 @@ pub const RwLock = struct {...@@ -180,13 +174,13 @@ pub const RwLock = struct {
180 return;174 return;
181 }175 }
182 // Release the lock again.176 // Release the lock again.
183 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);177 _ = @atomicRmw(u8, &self.writer_queue_empty_bit, .Xchg, 1, .SeqCst);
184 _ = @atomicRmw(u8, &self.shared_state, AtomicRmwOp.Xchg, State.Unlocked, AtomicOrder.SeqCst);178 _ = @atomicRmw(u8, &self.shared_state, .Xchg, State.Unlocked, .SeqCst);
185 continue;179 continue;
186 }180 }
187181
188 if (@atomicLoad(u8, &self.reader_queue_empty_bit, AtomicOrder.SeqCst) == 0) {182 if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
189 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {183 if (@cmpxchgStrong(u8, &self.shared_state, State.Unlocked, State.ReadLock, .SeqCst, .SeqCst) != null) {
190 // We did not obtain the lock. Great, the queues are someone else's problem.184 // We did not obtain the lock. Great, the queues are someone else's problem.
191 return;185 return;
192 }186 }
...@@ -199,8 +193,8 @@ pub const RwLock = struct {...@@ -199,8 +193,8 @@ pub const RwLock = struct {
199 return;193 return;
200 }194 }
201 // Release the lock again.195 // Release the lock again.
202 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);196 _ = @atomicRmw(u8, &self.reader_queue_empty_bit, .Xchg, 1, .SeqCst);
203 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, AtomicOrder.SeqCst, AtomicOrder.SeqCst) != null) {197 if (@cmpxchgStrong(u8, &self.shared_state, State.ReadLock, State.Unlocked, .SeqCst, .SeqCst) != null) {
204 // Didn't unlock. Someone else's problem.198 // Didn't unlock. Someone else's problem.
205 return;199 return;
206 }200 }
...@@ -215,6 +209,9 @@ test "std.event.RwLock" {...@@ -215,6 +209,9 @@ test "std.event.RwLock" {
215 // https://github.com/ziglang/zig/issues/2377209 // https://github.com/ziglang/zig/issues/2377
216 if (true) return error.SkipZigTest;210 if (true) return error.SkipZigTest;
217211
212 // https://github.com/ziglang/zig/issues/1908
213 if (builtin.single_threaded) return error.SkipZigTest;
214
218 const allocator = std.heap.direct_allocator;215 const allocator = std.heap.direct_allocator;
219216
220 var loop: Loop = undefined;217 var loop: Loop = undefined;
...@@ -224,8 +221,7 @@ test "std.event.RwLock" {...@@ -224,8 +221,7 @@ test "std.event.RwLock" {
224 var lock = RwLock.init(&loop);221 var lock = RwLock.init(&loop);
225 defer lock.deinit();222 defer lock.deinit();
226223
227 const handle = try async<allocator> testLock(&loop, &lock);224 const handle = testLock(&loop, &lock);
228 defer cancel handle;
229 loop.run();225 loop.run();
230226
231 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;227 const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len;
...@@ -233,28 +229,31 @@ test "std.event.RwLock" {...@@ -233,28 +229,31 @@ test "std.event.RwLock" {
233}229}
234230
235async fn testLock(loop: *Loop, lock: *RwLock) void {231async fn testLock(loop: *Loop, lock: *RwLock) void {
236 // TODO explicitly put next tick node memory in the coroutine frame #1194
237 suspend {
238 resume @handle();
239 }
240
241 var read_nodes: [100]Loop.NextTickNode = undefined;232 var read_nodes: [100]Loop.NextTickNode = undefined;
242 for (read_nodes) |*read_node| {233 for (read_nodes) |*read_node| {
243 read_node.data = async readRunner(lock) catch @panic("out of memory");234 const frame = loop.allocator.create(@Frame(readRunner)) catch @panic("memory");
235 read_node.data = frame;
236 frame.* = async readRunner(lock);
244 loop.onNextTick(read_node);237 loop.onNextTick(read_node);
245 }238 }
246239
247 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;240 var write_nodes: [shared_it_count]Loop.NextTickNode = undefined;
248 for (write_nodes) |*write_node| {241 for (write_nodes) |*write_node| {
249 write_node.data = async writeRunner(lock) catch @panic("out of memory");242 const frame = loop.allocator.create(@Frame(writeRunner)) catch @panic("memory");
243 write_node.data = frame;
244 frame.* = async writeRunner(lock);
250 loop.onNextTick(write_node);245 loop.onNextTick(write_node);
251 }246 }
252247
253 for (write_nodes) |*write_node| {248 for (write_nodes) |*write_node| {
254 await @ptrCast(promise->void, write_node.data);249 const casted = @ptrCast(*const @Frame(writeRunner), write_node.data);
250 await casted;
251 loop.allocator.destroy(casted);
255 }252 }
256 for (read_nodes) |*read_node| {253 for (read_nodes) |*read_node| {
257 await @ptrCast(promise->void, read_node.data);254 const casted = @ptrCast(*const @Frame(readRunner), read_node.data);
255 await casted;
256 loop.allocator.destroy(casted);
258 }257 }
259}258}
260259
...@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {...@@ -269,7 +268,7 @@ async fn writeRunner(lock: *RwLock) void {
269 var i: usize = 0;268 var i: usize = 0;
270 while (i < shared_test_data.len) : (i += 1) {269 while (i < shared_test_data.len) : (i += 1) {
271 std.time.sleep(100 * std.time.microsecond);270 std.time.sleep(100 * std.time.microsecond);
272 const lock_promise = async lock.acquireWrite() catch @panic("out of memory");271 const lock_promise = async lock.acquireWrite();
273 const handle = await lock_promise;272 const handle = await lock_promise;
274 defer handle.release();273 defer handle.release();
275274
...@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {...@@ -287,7 +286,7 @@ async fn readRunner(lock: *RwLock) void {
287286
288 var i: usize = 0;287 var i: usize = 0;
289 while (i < shared_test_data.len) : (i += 1) {288 while (i < shared_test_data.len) : (i += 1) {
290 const lock_promise = async lock.acquireRead() catch @panic("out of memory");289 const lock_promise = async lock.acquireRead();
291 const handle = await lock_promise;290 const handle = await lock_promise;
292 defer handle.release();291 defer handle.release();
293292
std/event/rwlocked.zig+1-1
...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;...@@ -3,7 +3,7 @@ const RwLock = std.event.RwLock;
3const Loop = std.event.Loop;3const Loop = std.event.Loop;
44
5/// Thread-safe async/await RW lock that protects one piece of data.5/// Thread-safe async/await RW lock that protects one piece of data.
6/// coroutines which are waiting for the lock are suspended, and6/// Functions which are waiting for the lock are suspended, and
7/// are resumed when the lock is released, in order.7/// are resumed when the lock is released, in order.
8pub fn RwLocked(comptime T: type) type {8pub fn RwLocked(comptime T: type) type {
9 return struct {9 return struct {
std/fmt.zig-3
...@@ -328,9 +328,6 @@ pub fn formatType(...@@ -328,9 +328,6 @@ pub fn formatType(
328 try output(context, "error.");328 try output(context, "error.");
329 return output(context, @errorName(value));329 return output(context, @errorName(value));
330 },330 },
331 .Promise => {
332 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
333 },
334 .Enum => {331 .Enum => {
335 if (comptime std.meta.trait.hasFn("format")(T)) {332 if (comptime std.meta.trait.hasFn("format")(T)) {
336 return value.format(fmt, options, context, Errors, output);333 return value.format(fmt, options, context, Errors, output);
std/hash.zig+9
...@@ -1,6 +1,9 @@...@@ -1,6 +1,9 @@
1const adler = @import("hash/adler.zig");1const adler = @import("hash/adler.zig");
2pub const Adler32 = adler.Adler32;2pub const Adler32 = adler.Adler32;
33
4const auto_hash = @import("hash/auto_hash.zig");
5pub const autoHash = auto_hash.autoHash;
6
4// pub for polynomials + generic crc32 construction7// pub for polynomials + generic crc32 construction
5pub const crc = @import("hash/crc.zig");8pub const crc = @import("hash/crc.zig");
6pub const Crc32 = crc.Crc32;9pub const Crc32 = crc.Crc32;
...@@ -16,6 +19,7 @@ pub const SipHash128 = siphash.SipHash128;...@@ -16,6 +19,7 @@ pub const SipHash128 = siphash.SipHash128;
1619
17pub const murmur = @import("hash/murmur.zig");20pub const murmur = @import("hash/murmur.zig");
18pub const Murmur2_32 = murmur.Murmur2_32;21pub const Murmur2_32 = murmur.Murmur2_32;
22
19pub const Murmur2_64 = murmur.Murmur2_64;23pub const Murmur2_64 = murmur.Murmur2_64;
20pub const Murmur3_32 = murmur.Murmur3_32;24pub const Murmur3_32 = murmur.Murmur3_32;
2125
...@@ -23,11 +27,16 @@ pub const cityhash = @import("hash/cityhash.zig");...@@ -23,11 +27,16 @@ pub const cityhash = @import("hash/cityhash.zig");
23pub const CityHash32 = cityhash.CityHash32;27pub const CityHash32 = cityhash.CityHash32;
24pub const CityHash64 = cityhash.CityHash64;28pub const CityHash64 = cityhash.CityHash64;
2529
30const wyhash = @import("hash/wyhash.zig");
31pub const Wyhash = wyhash.Wyhash;
32
26test "hash" {33test "hash" {
27 _ = @import("hash/adler.zig");34 _ = @import("hash/adler.zig");
35 _ = @import("hash/auto_hash.zig");
28 _ = @import("hash/crc.zig");36 _ = @import("hash/crc.zig");
29 _ = @import("hash/fnv.zig");37 _ = @import("hash/fnv.zig");
30 _ = @import("hash/siphash.zig");38 _ = @import("hash/siphash.zig");
31 _ = @import("hash/murmur.zig");39 _ = @import("hash/murmur.zig");
32 _ = @import("hash/cityhash.zig");40 _ = @import("hash/cityhash.zig");
41 _ = @import("hash/wyhash.zig");
33}42}
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;...@@ -4,6 +4,9 @@ const assert = debug.assert;
4const testing = std.testing;4const testing = std.testing;
5const math = std.math;5const math = std.math;
6const mem = std.mem;6const mem = std.mem;
7const meta = std.meta;
8const autoHash = std.hash.autoHash;
9const Wyhash = std.hash.Wyhash;
7const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
8const builtin = @import("builtin");11const builtin = @import("builtin");
912
...@@ -448,15 +451,17 @@ test "iterator hash map" {...@@ -448,15 +451,17 @@ test "iterator hash map" {
448 try reset_map.putNoClobber(2, 22);451 try reset_map.putNoClobber(2, 22);
449 try reset_map.putNoClobber(3, 33);452 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.
451 var keys = [_]i32{456 var keys = [_]i32{
457 1,
452 3,458 3,
453 2,459 2,
454 1,
455 };460 };
456 var values = [_]i32{461 var values = [_]i32{
462 11,
457 33,463 33,
458 22,464 22,
459 11,
460 };465 };
461466
462 var it = reset_map.iterator();467 var it = reset_map.iterator();
...@@ -518,8 +523,9 @@ pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) {...@@ -518,8 +523,9 @@ pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) {
518pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {523pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
519 return struct {524 return struct {
520 fn hash(key: K) u32 {525 fn hash(key: K) u32 {
521 comptime var rng = comptime std.rand.DefaultPrng.init(0);526 var hasher = Wyhash.init(0);
522 return autoHash(key, &rng.random, u32);527 autoHash(&hasher, key);
528 return @truncate(u32, hasher.final());
523 }529 }
524 }.hash;530 }.hash;
525}531}
...@@ -527,114 +533,7 @@ pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {...@@ -527,114 +533,7 @@ pub fn getAutoHashFn(comptime K: type) (fn (K) u32) {
527pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {533pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
528 return struct {534 return struct {
529 fn eql(a: K, b: K) bool {535 fn eql(a: K, b: K) bool {
530 return autoEql(a, b);536 return meta.eql(a, b);
531 }537 }
532 }.eql;538 }.eql;
533}539}
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" {...@@ -102,9 +102,19 @@ test "HeaderEntry" {
102 testing.expectEqualSlices(u8, "x", e.value);102 testing.expectEqualSlices(u8, "x", e.value);
103}103}
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
105const HeaderList = std.ArrayList(HeaderEntry);115const HeaderList = std.ArrayList(HeaderEntry);
106const HeaderIndexList = std.ArrayList(usize);116const HeaderIndexList = std.ArrayList(usize);
107const HeaderIndex = std.AutoHashMap([]const u8, HeaderIndexList);117const HeaderIndex = std.HashMap([]const u8, HeaderIndexList, stringHash, stringEql);
108118
109pub const Headers = struct {119pub const Headers = struct {
110 // the owned header field name is stored in the index as part of the key120 // 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 {...@@ -242,12 +242,76 @@ pub fn floatExponentBits(comptime T: type) comptime_int {
242 };242 };
243}243}
244244
245pub fn min(x: var, y: var) @typeOf(x + y) {245/// Given two types, returns the smallest one which is capable of holding the
246 return if (x < y) x else y;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 }
247}283}
248284
249test "math.min" {285test "math.min" {
250 testing.expect(min(i32(-1), i32(2)) == -1);286 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 }
251}315}
252316
253pub fn max(x: var, y: var) @typeOf(x + y) {317pub fn max(x: var, y: var) @typeOf(x + y) {
...@@ -309,7 +373,7 @@ test "math.shl" {...@@ -309,7 +373,7 @@ test "math.shl" {
309}373}
310374
311/// Shifts right. Overflowed bits are truncated.375/// 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.
313pub fn shr(comptime T: type, a: T, shift_amt: var) T {377pub fn shr(comptime T: type, a: T, shift_amt: var) T {
314 const abs_shift_amt = absCast(shift_amt);378 const abs_shift_amt = absCast(shift_amt);
315 const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt);379 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 {...@@ -104,8 +104,7 @@ pub fn Child(comptime T: type) type {
104 TypeId.Array => |info| info.child,104 TypeId.Array => |info| info.child,
105 TypeId.Pointer => |info| info.child,105 TypeId.Pointer => |info| info.child,
106 TypeId.Optional => |info| info.child,106 TypeId.Optional => |info| info.child,
107 TypeId.Promise => |info| if (info.child) |child| child else null,107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
108 else => @compileError("Expected promise, pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),
109 };108 };
110}109}
111110
...@@ -114,7 +113,6 @@ test "std.meta.Child" {...@@ -114,7 +113,6 @@ test "std.meta.Child" {
114 testing.expect(Child(*u8) == u8);113 testing.expect(Child(*u8) == u8);
115 testing.expect(Child([]u8) == u8);114 testing.expect(Child([]u8) == u8);
116 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
117 testing.expect(Child(promise->u8) == u8);
118}116}
119117
120pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
std/os.zig+13
...@@ -120,6 +120,19 @@ pub fn getrandom(buf: []u8) GetRandomError!void {...@@ -120,6 +120,19 @@ pub fn getrandom(buf: []u8) GetRandomError!void {
120 }120 }
121 }121 }
122 }122 }
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 }
123 if (wasi.is_the_target) {136 if (wasi.is_the_target) {
124 switch (wasi.random_get(buf.ptr, buf.len)) {137 switch (wasi.random_get(buf.ptr, buf.len)) {
125 0 => return,138 0 => return,
std/os/bits/netbsd.zig+59
...@@ -760,3 +760,62 @@ pub const stack_t = extern struct {...@@ -760,3 +760,62 @@ pub const stack_t = extern struct {
760 ss_size: isize,760 ss_size: isize,
761 ss_flags: i32,761 ss_flags: i32,
762};762};
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) {...@@ -5,4 +5,4 @@ pub const is_the_target = switch (builtin.os) {
5 else => false,5 else => false,
6};6};
7pub usingnamespace std.c;7pub 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");...@@ -2,4 +2,4 @@ const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3pub const is_the_target = builtin.os == .freebsd;3pub const is_the_target = builtin.os == .freebsd;
4pub usingnamespace std.c;4pub 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");...@@ -2,3 +2,4 @@ const builtin = @import("builtin");
2const std = @import("../std.zig");2const std = @import("../std.zig");
3pub const is_the_target = builtin.os == .netbsd;3pub const is_the_target = builtin.os == .netbsd;
4pub usingnamespace std.c;4pub usingnamespace std.c;
5pub usingnamespace @import("bits.zig");
std/os/windows.zig+12-4
...@@ -138,10 +138,19 @@ pub const RtlGenRandomError = error{Unexpected};...@@ -138,10 +138,19 @@ pub const RtlGenRandomError = error{Unexpected};
138/// https://github.com/rust-lang-nursery/rand/issues/111138/// https://github.com/rust-lang-nursery/rand/issues/111
139/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270139/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
140pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {140pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
141 if (advapi32.RtlGenRandom(output.ptr, output.len) == 0) {141 var total_read: usize = 0;
142 switch (kernel32.GetLastError()) {142 var buff: []u8 = output[0..];
143 else => |err| return unexpectedError(err),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());
144 }150 }
151
152 total_read += to_read;
153 buff = buff[to_read..];
145 }154 }
146}155}
147156
...@@ -866,7 +875,6 @@ pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {...@@ -866,7 +875,6 @@ pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
866 return error.Unexpected;875 return error.Unexpected;
867}876}
868877
869
870/// Call this when you made a windows NtDll call878/// Call this when you made a windows NtDll call
871/// and you get an unexpected status.879/// and you get an unexpected status.
872pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {880pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
std/os/windows/advapi32.zig+1-1
...@@ -19,5 +19,5 @@ pub extern "advapi32" stdcallcc fn RegQueryValueExW(...@@ -19,5 +19,5 @@ pub extern "advapi32" stdcallcc fn RegQueryValueExW(
1919
20// RtlGenRandom is known as SystemFunction036 under advapi3220// RtlGenRandom is known as SystemFunction036 under advapi32
21// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */21// 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;
23pub const RtlGenRandom = SystemFunction036;23pub const RtlGenRandom = SystemFunction036;
std/os/windows/bits.zig+2-2
...@@ -209,7 +209,7 @@ pub const FILE_INFORMATION_CLASS = extern enum {...@@ -209,7 +209,7 @@ pub const FILE_INFORMATION_CLASS = extern enum {
209 FileLinkInformationExBypassAccessCheck,209 FileLinkInformationExBypassAccessCheck,
210 FileStorageReserveIdInformation,210 FileStorageReserveIdInformation,
211 FileCaseSensitiveInformationForceAccessCheck,211 FileCaseSensitiveInformationForceAccessCheck,
212 FileMaximumInformation212 FileMaximumInformation,
213};213};
214214
215pub const OVERLAPPED = extern struct {215pub const OVERLAPPED = extern struct {
...@@ -731,4 +731,4 @@ pub const UNICODE_STRING = extern struct {...@@ -731,4 +731,4 @@ pub const UNICODE_STRING = extern struct {
731 Length: USHORT,731 Length: USHORT,
732 MaximumLength: USHORT,732 MaximumLength: USHORT,
733 Buffer: [*]WCHAR,733 Buffer: [*]WCHAR,
734};
\ No newline at end of file
734};
std/os/windows/ntdll.zig+8-2
...@@ -1,7 +1,13 @@...@@ -1,7 +1,13 @@
1usingnamespace @import("bits.zig");1usingnamespace @import("bits.zig");
22
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;3pub 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;
5pub extern "NtDll" stdcallcc fn NtCreateFile(11pub extern "NtDll" stdcallcc fn NtCreateFile(
6 FileHandle: *HANDLE,12 FileHandle: *HANDLE,
7 DesiredAccess: ACCESS_MASK,13 DesiredAccess: ACCESS_MASK,
...@@ -15,4 +21,4 @@ pub extern "NtDll" stdcallcc fn NtCreateFile(...@@ -15,4 +21,4 @@ pub extern "NtDll" stdcallcc fn NtCreateFile(
15 EaBuffer: *c_void,21 EaBuffer: *c_void,
16 EaLength: ULONG,22 EaLength: ULONG,
17) NTSTATUS;23) 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,5 +1,5 @@
1/// The operation completed successfully. 1/// The operation completed successfully.
2pub const SUCCESS = 0x00000000;2pub const SUCCESS = 0x00000000;
33
4/// The data was too large to fit into the specified buffer.4/// 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" {...@@ -549,7 +549,6 @@ test "rb" {
549 }549 }
550}550}
551551
552
553test "inserting and looking up" {552test "inserting and looking up" {
554 var tree: Tree = undefined;553 var tree: Tree = undefined;
555 tree.init(testCompare);554 tree.init(testCompare);
std/testing.zig+26-25
...@@ -25,36 +25,37 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {...@@ -25,36 +25,37 @@ pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
25/// The types must match exactly.25/// The types must match exactly.
26pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {26pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
27 switch (@typeInfo(@typeOf(actual))) {27 switch (@typeInfo(@typeOf(actual))) {
28 TypeId.NoReturn,28 .NoReturn,
29 TypeId.BoundFn,29 .BoundFn,
30 TypeId.ArgTuple,30 .ArgTuple,
31 TypeId.Opaque,31 .Opaque,
32 .Frame,
33 .AnyFrame,
32 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),34 => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
3335
34 TypeId.Undefined,36 .Undefined,
35 TypeId.Null,37 .Null,
36 TypeId.Void,38 .Void,
37 => return,39 => return,
3840
39 TypeId.Type,41 .Type,
40 TypeId.Bool,42 .Bool,
41 TypeId.Int,43 .Int,
42 TypeId.Float,44 .Float,
43 TypeId.ComptimeFloat,45 .ComptimeFloat,
44 TypeId.ComptimeInt,46 .ComptimeInt,
45 TypeId.EnumLiteral,47 .EnumLiteral,
46 TypeId.Enum,48 .Enum,
47 TypeId.Fn,49 .Fn,
48 TypeId.Promise,50 .Vector,
49 TypeId.Vector,51 .ErrorSet,
50 TypeId.ErrorSet,
51 => {52 => {
52 if (actual != expected) {53 if (actual != expected) {
53 std.debug.panic("expected {}, found {}", expected, actual);54 std.debug.panic("expected {}, found {}", expected, actual);
54 }55 }
55 },56 },
5657
57 TypeId.Pointer => |pointer| {58 .Pointer => |pointer| {
58 switch (pointer.size) {59 switch (pointer.size) {
59 builtin.TypeInfo.Pointer.Size.One,60 builtin.TypeInfo.Pointer.Size.One,
60 builtin.TypeInfo.Pointer.Size.Many,61 builtin.TypeInfo.Pointer.Size.Many,
...@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -76,22 +77,22 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
76 }77 }
77 },78 },
7879
79 TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual),80 .Array => |array| expectEqualSlices(array.child, &expected, &actual),
8081
81 TypeId.Struct => |structType| {82 .Struct => |structType| {
82 inline for (structType.fields) |field| {83 inline for (structType.fields) |field| {
83 expectEqual(@field(expected, field.name), @field(actual, field.name));84 expectEqual(@field(expected, field.name), @field(actual, field.name));
84 }85 }
85 },86 },
8687
87 TypeId.Union => |union_info| {88 .Union => |union_info| {
88 if (union_info.tag_type == null) {89 if (union_info.tag_type == null) {
89 @compileError("Unable to compare untagged union values");90 @compileError("Unable to compare untagged union values");
90 }91 }
91 @compileError("TODO implement testing.expectEqual for tagged unions");92 @compileError("TODO implement testing.expectEqual for tagged unions");
92 },93 },
9394
94 TypeId.Optional => {95 .Optional => {
95 if (expected) |expected_payload| {96 if (expected) |expected_payload| {
96 if (actual) |actual_payload| {97 if (actual) |actual_payload| {
97 expectEqual(expected_payload, actual_payload);98 expectEqual(expected_payload, actual_payload);
...@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -105,7 +106,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
105 }106 }
106 },107 },
107108
108 TypeId.ErrorUnion => {109 .ErrorUnion => {
109 if (expected) |expected_payload| {110 if (expected) |expected_payload| {
110 if (actual) |actual_payload| {111 if (actual) |actual_payload| {
111 expectEqual(expected_payload, actual_payload);112 expectEqual(expected_payload, actual_payload);
std/zig/ast.zig+10-43
...@@ -400,7 +400,7 @@ pub const Node = struct {...@@ -400,7 +400,7 @@ pub const Node = struct {
400 VarType,400 VarType,
401 ErrorType,401 ErrorType,
402 FnProto,402 FnProto,
403 PromiseType,403 AnyFrameType,
404404
405 // Primary expressions405 // Primary expressions
406 IntegerLiteral,406 IntegerLiteral,
...@@ -434,7 +434,6 @@ pub const Node = struct {...@@ -434,7 +434,6 @@ pub const Node = struct {
434 ErrorTag,434 ErrorTag,
435 AsmInput,435 AsmInput,
436 AsmOutput,436 AsmOutput,
437 AsyncAttribute,
438 ParamDecl,437 ParamDecl,
439 FieldInitializer,438 FieldInitializer,
440 };439 };
...@@ -838,36 +837,6 @@ pub const Node = struct {...@@ -838,36 +837,6 @@ pub const Node = struct {
838 }837 }
839 };838 };
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
871 pub const FnProto = struct {840 pub const FnProto = struct {
872 base: Node,841 base: Node,
873 doc_comments: ?*DocComment,842 doc_comments: ?*DocComment,
...@@ -879,7 +848,6 @@ pub const Node = struct {...@@ -879,7 +848,6 @@ pub const Node = struct {
879 var_args_token: ?TokenIndex,848 var_args_token: ?TokenIndex,
880 extern_export_inline_token: ?TokenIndex,849 extern_export_inline_token: ?TokenIndex,
881 cc_token: ?TokenIndex,850 cc_token: ?TokenIndex,
882 async_attr: ?*AsyncAttribute,
883 body_node: ?*Node,851 body_node: ?*Node,
884 lib_name: ?*Node, // populated if this is an extern declaration852 lib_name: ?*Node, // populated if this is an extern declaration
885 align_expr: ?*Node, // populated if align(A) is present853 align_expr: ?*Node, // populated if align(A) is present
...@@ -935,7 +903,6 @@ pub const Node = struct {...@@ -935,7 +903,6 @@ pub const Node = struct {
935903
936 pub fn firstToken(self: *const FnProto) TokenIndex {904 pub fn firstToken(self: *const FnProto) TokenIndex {
937 if (self.visib_token) |visib_token| return visib_token;905 if (self.visib_token) |visib_token| return visib_token;
938 if (self.async_attr) |async_attr| return async_attr.firstToken();
939 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;906 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
940 assert(self.lib_name == null);907 assert(self.lib_name == null);
941 if (self.cc_token) |cc_token| return cc_token;908 if (self.cc_token) |cc_token| return cc_token;
...@@ -952,9 +919,9 @@ pub const Node = struct {...@@ -952,9 +919,9 @@ pub const Node = struct {
952 }919 }
953 };920 };
954921
955 pub const PromiseType = struct {922 pub const AnyFrameType = struct {
956 base: Node,923 base: Node,
957 promise_token: TokenIndex,924 anyframe_token: TokenIndex,
958 result: ?Result,925 result: ?Result,
959926
960 pub const Result = struct {927 pub const Result = struct {
...@@ -962,7 +929,7 @@ pub const Node = struct {...@@ -962,7 +929,7 @@ pub const Node = struct {
962 return_type: *Node,929 return_type: *Node,
963 };930 };
964931
965 pub fn iterate(self: *PromiseType, index: usize) ?*Node {932 pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
966 var i = index;933 var i = index;
967934
968 if (self.result) |result| {935 if (self.result) |result| {
...@@ -973,13 +940,13 @@ pub const Node = struct {...@@ -973,13 +940,13 @@ pub const Node = struct {
973 return null;940 return null;
974 }941 }
975942
976 pub fn firstToken(self: *const PromiseType) TokenIndex {943 pub fn firstToken(self: *const AnyFrameType) TokenIndex {
977 return self.promise_token;944 return self.anyframe_token;
978 }945 }
979946
980 pub fn lastToken(self: *const PromiseType) TokenIndex {947 pub fn lastToken(self: *const AnyFrameType) TokenIndex {
981 if (self.result) |result| return result.return_type.lastToken();948 if (self.result) |result| return result.return_type.lastToken();
982 return self.promise_token;949 return self.anyframe_token;
983 }950 }
984 };951 };
985952
...@@ -1699,7 +1666,7 @@ pub const Node = struct {...@@ -1699,7 +1666,7 @@ pub const Node = struct {
16991666
1700 pub const Call = struct {1667 pub const Call = struct {
1701 params: ParamList,1668 params: ParamList,
1702 async_attr: ?*AsyncAttribute,1669 async_token: ?TokenIndex,
17031670
1704 pub const ParamList = SegmentedList(*Node, 2);1671 pub const ParamList = SegmentedList(*Node, 2);
1705 };1672 };
...@@ -1752,7 +1719,7 @@ pub const Node = struct {...@@ -1752,7 +1719,7 @@ pub const Node = struct {
17521719
1753 pub fn firstToken(self: *const SuffixOp) TokenIndex {1720 pub fn firstToken(self: *const SuffixOp) TokenIndex {
1754 switch (self.op) {1721 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,
1756 else => {},1723 else => {},
1757 }1724 }
1758 return self.lhs.firstToken();1725 return self.lhs.firstToken();
std/zig/parse.zig+37-87
...@@ -277,7 +277,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -277,7 +277,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
277277
278/// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)278/// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
279fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {279fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
280 const cc = try parseFnCC(arena, it, tree);280 const cc = parseFnCC(arena, it, tree);
281 const fn_token = eatToken(it, .Keyword_fn) orelse {281 const fn_token = eatToken(it, .Keyword_fn) orelse {
282 if (cc == null) return null else return error.ParseError;282 if (cc == null) return null else return error.ParseError;
283 };283 };
...@@ -320,7 +320,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -320,7 +320,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
320 .var_args_token = var_args_token,320 .var_args_token = var_args_token,
321 .extern_export_inline_token = null,321 .extern_export_inline_token = null,
322 .cc_token = null,322 .cc_token = null,
323 .async_attr = null,
324 .body_node = null,323 .body_node = null,
325 .lib_name = null,324 .lib_name = null,
326 .align_expr = align_expr,325 .align_expr = align_expr,
...@@ -331,7 +330,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -331,7 +330,6 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
331 switch (kind) {330 switch (kind) {
332 .CC => |token| fn_proto_node.cc_token = token,331 .CC => |token| fn_proto_node.cc_token = token,
333 .Extern => |token| fn_proto_node.extern_export_inline_token = token,332 .Extern => |token| fn_proto_node.extern_export_inline_token = token,
334 .Async => |node| fn_proto_node.async_attr = node,
335 }333 }
336 }334 }
337335
...@@ -814,7 +812,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -814,7 +812,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
814/// <- AsmExpr812/// <- AsmExpr
815/// / IfExpr813/// / IfExpr
816/// / KEYWORD_break BreakLabel? Expr?814/// / KEYWORD_break BreakLabel? Expr?
817/// / KEYWORD_cancel Expr
818/// / KEYWORD_comptime Expr815/// / KEYWORD_comptime Expr
819/// / KEYWORD_continue BreakLabel?816/// / KEYWORD_continue BreakLabel?
820/// / KEYWORD_resume Expr817/// / KEYWORD_resume Expr
...@@ -839,20 +836,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -839,20 +836,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
839 return &node.base;836 return &node.base;
840 }837 }
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
856 if (eatToken(it, .Keyword_comptime)) |token| {839 if (eatToken(it, .Keyword_comptime)) |token| {
857 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{840 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
858 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },841 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
...@@ -1107,10 +1090,19 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -1107,10 +1090,19 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
1107}1090}
11081091
1109/// SuffixExpr1092/// SuffixExpr
1110/// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments1093/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
1111/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*1094/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
1112fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1095fn 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 }
1114 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr1106 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
1115 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{1107 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{
1116 .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index },1108 .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index },
...@@ -1131,7 +1123,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1131,7 +1123,6 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1131 });1123 });
1132 return null;1124 return null;
1133 };1125 };
1134
1135 const node = try arena.create(Node.SuffixOp);1126 const node = try arena.create(Node.SuffixOp);
1136 node.* = Node.SuffixOp{1127 node.* = Node.SuffixOp{
1137 .base = Node{ .id = .SuffixOp },1128 .base = Node{ .id = .SuffixOp },
...@@ -1139,14 +1130,13 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1139,14 +1130,13 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1139 .op = Node.SuffixOp.Op{1130 .op = Node.SuffixOp.Op{
1140 .Call = Node.SuffixOp.Op.Call{1131 .Call = Node.SuffixOp.Op.Call{
1141 .params = params.list,1132 .params = params.list,
1142 .async_attr = async_node.cast(Node.AsyncAttribute).?,1133 .async_token = async_token,
1143 },1134 },
1144 },1135 },
1145 .rtoken = params.rparen,1136 .rtoken = params.rparen,
1146 };1137 };
1147 return &node.base;1138 return &node.base;
1148 }1139 }
1149
1150 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {1140 if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| {
1151 var res = expr;1141 var res = expr;
11521142
...@@ -1168,7 +1158,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1168,7 +1158,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1168 .op = Node.SuffixOp.Op{1158 .op = Node.SuffixOp.Op{
1169 .Call = Node.SuffixOp.Op.Call{1159 .Call = Node.SuffixOp.Op.Call{
1170 .params = params.list,1160 .params = params.list,
1171 .async_attr = null,1161 .async_token = null,
1172 },1162 },
1173 },1163 },
1174 .rtoken = params.rparen,1164 .rtoken = params.rparen,
...@@ -1201,7 +1191,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1201,7 +1191,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1201/// / KEYWORD_error DOT IDENTIFIER1191/// / KEYWORD_error DOT IDENTIFIER
1202/// / KEYWORD_false1192/// / KEYWORD_false
1203/// / KEYWORD_null1193/// / KEYWORD_null
1204/// / KEYWORD_promise1194/// / KEYWORD_anyframe
1205/// / KEYWORD_true1195/// / KEYWORD_true
1206/// / KEYWORD_undefined1196/// / KEYWORD_undefined
1207/// / KEYWORD_unreachable1197/// / KEYWORD_unreachable
...@@ -1256,11 +1246,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N...@@ -1256,11 +1246,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1256 }1246 }
1257 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);1247 if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
1258 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);1248 if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
1259 if (eatToken(it, .Keyword_promise)) |token| {1249 if (eatToken(it, .Keyword_anyframe)) |token| {
1260 const node = try arena.create(Node.PromiseType);1250 const node = try arena.create(Node.AnyFrameType);
1261 node.* = Node.PromiseType{1251 node.* = Node.AnyFrameType{
1262 .base = Node{ .id = .PromiseType },1252 .base = Node{ .id = .AnyFrameType },
1263 .promise_token = token,1253 .anyframe_token = token,
1264 .result = null,1254 .result = null,
1265 };1255 };
1266 return &node.base;1256 return &node.base;
...@@ -1668,36 +1658,18 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1668,36 +1658,18 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1668/// <- KEYWORD_nakedcc1658/// <- KEYWORD_nakedcc
1669/// / KEYWORD_stdcallcc1659/// / KEYWORD_stdcallcc
1670/// / KEYWORD_extern1660/// / KEYWORD_extern
1671/// / KEYWORD_async (LARROW TypeExpr RARROW)?1661/// / KEYWORD_async
1672fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?FnCC {1662fn parseFnCC(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?FnCC {
1673 if (eatToken(it, .Keyword_nakedcc)) |token| return FnCC{ .CC = token };1663 if (eatToken(it, .Keyword_nakedcc)) |token| return FnCC{ .CC = token };
1674 if (eatToken(it, .Keyword_stdcallcc)) |token| return FnCC{ .CC = token };1664 if (eatToken(it, .Keyword_stdcallcc)) |token| return FnCC{ .CC = token };
1675 if (eatToken(it, .Keyword_extern)) |token| return FnCC{ .Extern = token };1665 if (eatToken(it, .Keyword_extern)) |token| return FnCC{ .Extern = token };
1676 if (eatToken(it, .Keyword_async)) |token| {1666 if (eatToken(it, .Keyword_async)) |token| return FnCC{ .CC = 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 }
1694 return null;1667 return null;
1695}1668}
16961669
1697const FnCC = union(enum) {1670const FnCC = union(enum) {
1698 CC: TokenIndex,1671 CC: TokenIndex,
1699 Extern: TokenIndex,1672 Extern: TokenIndex,
1700 Async: *Node.AsyncAttribute,
1701};1673};
17021674
1703/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType1675/// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
...@@ -2194,7 +2166,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2194,7 +2166,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
21942166
2195/// PrefixTypeOp2167/// PrefixTypeOp
2196/// <- QUESTIONMARK2168/// <- QUESTIONMARK
2197/// / KEYWORD_promise MINUSRARROW2169/// / KEYWORD_anyframe MINUSRARROW
2198/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2170/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2199/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2171/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2200fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2172fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
...@@ -2209,20 +2181,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2209,20 +2181,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2209 return &node.base;2181 return &node.base;
2210 }2182 }
22112183
2212 // TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or2184 // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
2213 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).2185 // .return_type more difficult for the caller (see parsePrefixOpExpr helper).
2214 // Consider making the PromiseType a member of PrefixOp and add a2186 // Consider making the AnyFrameType a member of PrefixOp and add a
2215 // PrefixOp.PromiseType variant?2187 // PrefixOp.AnyFrameType variant?
2216 if (eatToken(it, .Keyword_promise)) |token| {2188 if (eatToken(it, .Keyword_anyframe)) |token| {
2217 const arrow = eatToken(it, .Arrow) orelse {2189 const arrow = eatToken(it, .Arrow) orelse {
2218 putBackToken(it, token);2190 putBackToken(it, token);
2219 return null;2191 return null;
2220 };2192 };
2221 const node = try arena.create(Node.PromiseType);2193 const node = try arena.create(Node.AnyFrameType);
2222 node.* = Node.PromiseType{2194 node.* = Node.AnyFrameType{
2223 .base = Node{ .id = .PromiseType },2195 .base = Node{ .id = .AnyFrameType },
2224 .promise_token = token,2196 .anyframe_token = token,
2225 .result = Node.PromiseType.Result{2197 .result = Node.AnyFrameType.Result{
2226 .arrow_token = arrow,2198 .arrow_token = arrow,
2227 .return_type = undefined, // set by caller2199 .return_type = undefined, // set by caller
2228 },2200 },
...@@ -2424,28 +2396,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2424,28 +2396,6 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2424 return &node.base;2396 return &node.base;
2425}2397}
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
2449/// FnCallArguments <- LPAREN ExprList RPAREN2399/// FnCallArguments <- LPAREN ExprList RPAREN
2450/// ExprList <- (Expr COMMA)* Expr?2400/// ExprList <- (Expr COMMA)* Expr?
2451fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {2401fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList {
...@@ -2903,8 +2853,8 @@ fn parsePrefixOpExpr(...@@ -2903,8 +2853,8 @@ fn parsePrefixOpExpr(
2903 rightmost_op = rhs;2853 rightmost_op = rhs;
2904 } else break;2854 } else break;
2905 },2855 },
2906 .PromiseType => {2856 .AnyFrameType => {
2907 const prom = rightmost_op.cast(Node.PromiseType).?;2857 const prom = rightmost_op.cast(Node.AnyFrameType).?;
2908 if (try opParseFn(arena, it, tree)) |rhs| {2858 if (try opParseFn(arena, it, tree)) |rhs| {
2909 prom.result.?.return_type = rhs;2859 prom.result.?.return_type = rhs;
2910 rightmost_op = rhs;2860 rightmost_op = rhs;
...@@ -2922,8 +2872,8 @@ fn parsePrefixOpExpr(...@@ -2922,8 +2872,8 @@ fn parsePrefixOpExpr(
2922 .InvalidToken = AstError.InvalidToken{ .token = it.index },2872 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2923 });2873 });
2924 },2874 },
2925 .PromiseType => {2875 .AnyFrameType => {
2926 const prom = rightmost_op.cast(Node.PromiseType).?;2876 const prom = rightmost_op.cast(Node.AnyFrameType).?;
2927 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{2877 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
2928 .InvalidToken = AstError.InvalidToken{ .token = it.index },2878 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2929 });2879 });
std/zig/parser_test.zig+20-8
...@@ -8,6 +8,18 @@ test "zig fmt: change use to usingnamespace" {...@@ -8,6 +8,18 @@ test "zig fmt: change use to usingnamespace" {
8 );8 );
9}9}
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
11test "zig fmt: whitespace fixes" {23test "zig fmt: whitespace fixes" {
12 try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n",24 try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n",
13 \\test "" {25 \\test "" {
...@@ -210,7 +222,7 @@ test "zig fmt: spaces around slice operator" {...@@ -210,7 +222,7 @@ test "zig fmt: spaces around slice operator" {
210test "zig fmt: async call in if condition" {222test "zig fmt: async call in if condition" {
211 try testCanonical(223 try testCanonical(
212 \\comptime {224 \\comptime {
213 \\ if (async<a> b()) {225 \\ if (async b()) {
214 \\ a();226 \\ a();
215 \\ }227 \\ }
216 \\}228 \\}
...@@ -1118,7 +1130,7 @@ test "zig fmt: first line comment in struct initializer" {...@@ -1118,7 +1130,7 @@ test "zig fmt: first line comment in struct initializer" {
1118 \\pub async fn acquire(self: *Self) HeldLock {1130 \\pub async fn acquire(self: *Self) HeldLock {
1119 \\ return HeldLock{1131 \\ return HeldLock{
1120 \\ // guaranteed allocation elision1132 \\ // guaranteed allocation elision
1121 \\ .held = await (async self.lock.acquire() catch unreachable),1133 \\ .held = self.lock.acquire(),
1122 \\ .value = &self.private_data,1134 \\ .value = &self.private_data,
1123 \\ };1135 \\ };
1124 \\}1136 \\}
...@@ -1183,7 +1195,7 @@ test "zig fmt: resume from suspend block" {...@@ -1183,7 +1195,7 @@ test "zig fmt: resume from suspend block" {
1183 try testCanonical(1195 try testCanonical(
1184 \\fn foo() void {1196 \\fn foo() void {
1185 \\ suspend {1197 \\ suspend {
1186 \\ resume @handle();1198 \\ resume @frame();
1187 \\ }1199 \\ }
1188 \\}1200 \\}
1189 \\1201 \\
...@@ -2103,7 +2115,7 @@ test "zig fmt: inline asm" {...@@ -2103,7 +2115,7 @@ test "zig fmt: inline asm" {
2103 );2115 );
2104}2116}
21052117
2106test "zig fmt: coroutines" {2118test "zig fmt: async functions" {
2107 try testCanonical(2119 try testCanonical(
2108 \\async fn simpleAsyncFn() void {2120 \\async fn simpleAsyncFn() void {
2109 \\ const a = async a.b();2121 \\ const a = async a.b();
...@@ -2111,14 +2123,14 @@ test "zig fmt: coroutines" {...@@ -2111,14 +2123,14 @@ test "zig fmt: coroutines" {
2111 \\ suspend;2123 \\ suspend;
2112 \\ x += 1;2124 \\ x += 1;
2113 \\ suspend;2125 \\ suspend;
2114 \\ const p: promise->void = async simpleAsyncFn() catch unreachable;2126 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
2115 \\ await p;2127 \\ await p;
2116 \\}2128 \\}
2117 \\2129 \\
2118 \\test "coroutine suspend, resume, cancel" {2130 \\test "suspend, resume, await" {
2119 \\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();2131 \\ const p: anyframe = async testAsyncSeq();
2120 \\ resume p;2132 \\ resume p;
2121 \\ cancel p;2133 \\ await p;
2122 \\}2134 \\}
2123 \\2135 \\
2124 );2136 );
std/zig/render.zig+7-25
...@@ -284,20 +284,6 @@ fn renderExpression(...@@ -284,20 +284,6 @@ fn renderExpression(
284 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);284 return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
285 },285 },
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
301 ast.Node.Id.Suspend => {287 ast.Node.Id.Suspend => {
302 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);288 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
303289
...@@ -459,8 +445,8 @@ fn renderExpression(...@@ -459,8 +445,8 @@ fn renderExpression(
459445
460 switch (suffix_op.op) {446 switch (suffix_op.op) {
461 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {447 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
462 if (call_info.async_attr) |async_attr| {448 if (call_info.async_token) |async_token| {
463 try renderExpression(allocator, stream, tree, indent, start_col, &async_attr.base, Space.Space);449 try renderToken(tree, stream, async_token, indent, start_col, Space.Space);
464 }450 }
465451
466 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);452 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
...@@ -1121,10 +1107,6 @@ fn renderExpression(...@@ -1121,10 +1107,6 @@ fn renderExpression(
1121 try renderToken(tree, stream, cc_token, indent, start_col, Space.Space); // stdcallcc1107 try renderToken(tree, stream, cc_token, indent, start_col, Space.Space); // stdcallcc
1122 }1108 }
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
1128 const lparen = if (fn_proto.name_token) |name_token| blk: {1110 const lparen = if (fn_proto.name_token) |name_token| blk: {
1129 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn1111 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
1130 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name1112 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
...@@ -1205,15 +1187,15 @@ fn renderExpression(...@@ -1205,15 +1187,15 @@ fn renderExpression(
1205 }1187 }
1206 },1188 },
12071189
1208 ast.Node.Id.PromiseType => {1190 ast.Node.Id.AnyFrameType => {
1209 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);1191 const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
12101192
1211 if (promise_type.result) |result| {1193 if (anyframe_type.result) |result| {
1212 try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise1194 try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
1213 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->1195 try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
1214 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);1196 return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
1215 } else {1197 } else {
1216 return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise1198 return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
1217 }1199 }
1218 },1200 },
12191201
std/zig/tokenizer.zig+2-4
...@@ -15,12 +15,12 @@ pub const Token = struct {...@@ -15,12 +15,12 @@ pub const Token = struct {
15 Keyword{ .bytes = "align", .id = Id.Keyword_align },15 Keyword{ .bytes = "align", .id = Id.Keyword_align },
16 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },16 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
17 Keyword{ .bytes = "and", .id = Id.Keyword_and },17 Keyword{ .bytes = "and", .id = Id.Keyword_and },
18 Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
18 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },19 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
19 Keyword{ .bytes = "async", .id = Id.Keyword_async },20 Keyword{ .bytes = "async", .id = Id.Keyword_async },
20 Keyword{ .bytes = "await", .id = Id.Keyword_await },21 Keyword{ .bytes = "await", .id = Id.Keyword_await },
21 Keyword{ .bytes = "break", .id = Id.Keyword_break },22 Keyword{ .bytes = "break", .id = Id.Keyword_break },
22 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },23 Keyword{ .bytes = "catch", .id = Id.Keyword_catch },
23 Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel },
24 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },24 Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime },
25 Keyword{ .bytes = "const", .id = Id.Keyword_const },25 Keyword{ .bytes = "const", .id = Id.Keyword_const },
26 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },26 Keyword{ .bytes = "continue", .id = Id.Keyword_continue },
...@@ -42,7 +42,6 @@ pub const Token = struct {...@@ -42,7 +42,6 @@ pub const Token = struct {
42 Keyword{ .bytes = "or", .id = Id.Keyword_or },42 Keyword{ .bytes = "or", .id = Id.Keyword_or },
43 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },43 Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
44 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },44 Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
45 Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
46 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },45 Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
47 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },46 Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
48 Keyword{ .bytes = "return", .id = Id.Keyword_return },47 Keyword{ .bytes = "return", .id = Id.Keyword_return },
...@@ -151,7 +150,6 @@ pub const Token = struct {...@@ -151,7 +150,6 @@ pub const Token = struct {
151 Keyword_async,150 Keyword_async,
152 Keyword_await,151 Keyword_await,
153 Keyword_break,152 Keyword_break,
154 Keyword_cancel,
155 Keyword_catch,153 Keyword_catch,
156 Keyword_comptime,154 Keyword_comptime,
157 Keyword_const,155 Keyword_const,
...@@ -174,7 +172,7 @@ pub const Token = struct {...@@ -174,7 +172,7 @@ pub const Token = struct {
174 Keyword_or,172 Keyword_or,
175 Keyword_orelse,173 Keyword_orelse,
176 Keyword_packed,174 Keyword_packed,
177 Keyword_promise,175 Keyword_anyframe,
178 Keyword_pub,176 Keyword_pub,
179 Keyword_resume,177 Keyword_resume,
180 Keyword_return,178 Keyword_return,
test/compile_errors.zig+224-35
...@@ -2,6 +2,220 @@ const tests = @import("tests.zig");...@@ -2,6 +2,220 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "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
5 cases.add(219 cases.add(
6 "capture group on switch prong with incompatible payload types",220 "capture group on switch prong with incompatible payload types",
7 \\const Union = union(enum) {221 \\const Union = union(enum) {
...@@ -1319,24 +1533,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1319,24 +1533,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1319 );1533 );
13201534
1321 cases.add(1535 cases.add(
1322 "@handle() called outside of function definition",1536 "@frame() called outside of function definition",
1323 \\var handle_undef: promise = undefined;1537 \\var handle_undef: anyframe = undefined;
1324 \\var handle_dummy: promise = @handle();1538 \\var handle_dummy: anyframe = @frame();
1325 \\export fn entry() bool {1539 \\export fn entry() bool {
1326 \\ return handle_undef == handle_dummy;1540 \\ return handle_undef == handle_dummy;
1327 \\}1541 \\}
1328 ,1542 ,
1329 "tmp.zig:2:29: error: @handle() called outside of function definition",1543 "tmp.zig:2:30: error: @frame() called outside of function definition",
1330 );
1331
1332 cases.add(
1333 "@handle() in non-async function",
1334 \\export fn entry() bool {
1335 \\ var handle_undef: promise = undefined;
1336 \\ return handle_undef == @handle();
1337 \\}
1338 ,
1339 "tmp.zig:3:28: error: @handle() in non-async function",
1340 );1544 );
13411545
1342 cases.add(1546 cases.add(
...@@ -1712,15 +1916,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1712,15 +1916,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17121916
1713 cases.add(1917 cases.add(
1714 "suspend inside suspend block",1918 "suspend inside suspend block",
1715 \\const std = @import("std",);
1716 \\
1717 \\export fn entry() void {1919 \\export fn entry() void {
1718 \\ var buf: [500]u8 = undefined;1920 \\ _ = async foo();
1719 \\ var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
1720 \\ const p = (async<a> foo()) catch unreachable;
1721 \\ cancel p;
1722 \\}1921 \\}
1723 \\
1724 \\async fn foo() void {1922 \\async fn foo() void {
1725 \\ suspend {1923 \\ suspend {
1726 \\ suspend {1924 \\ suspend {
...@@ -1728,8 +1926,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1728,8 +1926,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1728 \\ }1926 \\ }
1729 \\}1927 \\}
1730 ,1928 ,
1731 "tmp.zig:12:9: error: cannot suspend inside suspend block",1929 "tmp.zig:6:9: error: cannot suspend inside suspend block",
1732 "tmp.zig:11:5: note: other suspend block here",1930 "tmp.zig:5:5: note: other suspend block here",
1733 );1931 );
17341932
1735 cases.add(1933 cases.add(
...@@ -1770,15 +1968,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1770,15 +1968,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
17701968
1771 cases.add(1969 cases.add(
1772 "returning error from void async function",1970 "returning error from void async function",
1773 \\const std = @import("std",);
1774 \\export fn entry() void {1971 \\export fn entry() void {
1775 \\ const p = async<std.debug.global_allocator> amain() catch unreachable;1972 \\ _ = async amain();
1776 \\}1973 \\}
1777 \\async fn amain() void {1974 \\async fn amain() void {
1778 \\ return error.ShouldBeCompileError;1975 \\ return error.ShouldBeCompileError;
1779 \\}1976 \\}
1780 ,1977 ,
1781 "tmp.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",1978 "tmp.zig:5:17: error: expected type 'void', found 'error{ShouldBeCompileError}'",
1782 );1979 );
17831980
1784 cases.add(1981 cases.add(
...@@ -3225,14 +3422,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3225,14 +3422,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3225 "tmp.zig:3:17: note: value 8 cannot fit into type u3",3422 "tmp.zig:3:17: note: value 8 cannot fit into type u3",
3226 );3423 );
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
3236 cases.add(3425 cases.add(
3237 "missing function call param",3426 "missing function call param",
3238 \\const Foo = struct {3427 \\const Foo = struct {
...@@ -3315,7 +3504,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3315,7 +3504,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3315 \\3504 \\
3316 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }3505 \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
3317 ,3506 ,
3318 "tmp.zig:5:18: error: unable to evaluate constant expression",3507 "tmp.zig:5:25: error: unable to evaluate constant expression",
3319 "tmp.zig:2:12: note: called from here",3508 "tmp.zig:2:12: note: called from here",
3320 "tmp.zig:2:8: note: called from here",3509 "tmp.zig:2:8: note: called from here",
3321 );3510 );
test/runtime_safety.zig+96-5
...@@ -1,6 +1,91 @@...@@ -1,6 +1,91 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("awaiting twice",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\var frame: anyframe = undefined;
9 \\
10 \\pub fn main() void {
11 \\ _ = async amain();
12 \\ resume frame;
13 \\}
14 \\
15 \\fn amain() void {
16 \\ var f = async func();
17 \\ await f;
18 \\ await f;
19 \\}
20 \\
21 \\fn func() void {
22 \\ suspend {
23 \\ frame = @frame();
24 \\ }
25 \\}
26 );
27
28 cases.addRuntimeSafety("@asyncCall with too small a frame",
29 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
30 \\ @import("std").os.exit(126);
31 \\}
32 \\pub fn main() void {
33 \\ var bytes: [1]u8 = undefined;
34 \\ var ptr = other;
35 \\ var frame = @asyncCall(&bytes, {}, ptr);
36 \\}
37 \\async fn other() void {
38 \\ suspend;
39 \\}
40 );
41
42 cases.addRuntimeSafety("resuming a function which is awaiting a frame",
43 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
44 \\ @import("std").os.exit(126);
45 \\}
46 \\pub fn main() void {
47 \\ var frame = async first();
48 \\ resume frame;
49 \\}
50 \\fn first() void {
51 \\ var frame = async other();
52 \\ await frame;
53 \\}
54 \\fn other() void {
55 \\ suspend;
56 \\}
57 );
58
59 cases.addRuntimeSafety("resuming a function which is awaiting a call",
60 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
61 \\ @import("std").os.exit(126);
62 \\}
63 \\pub fn main() void {
64 \\ var frame = async first();
65 \\ resume frame;
66 \\}
67 \\fn first() void {
68 \\ other();
69 \\}
70 \\fn other() void {
71 \\ suspend;
72 \\}
73 );
74
75 cases.addRuntimeSafety("invalid resume of async function",
76 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
77 \\ @import("std").os.exit(126);
78 \\}
79 \\pub fn main() void {
80 \\ var p = async suspendOnce();
81 \\ resume p; //ok
82 \\ resume p; //bad
83 \\}
84 \\fn suspendOnce() void {
85 \\ suspend;
86 \\}
87 );
88
4 cases.addRuntimeSafety(".? operator on null pointer",89 cases.addRuntimeSafety(".? operator on null pointer",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {90 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);91 \\ @import("std").os.exit(126);
...@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -483,23 +568,29 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
483 \\ std.os.exit(126);568 \\ std.os.exit(126);
484 \\}569 \\}
485 \\570 \\
571 \\var failing_frame: @Frame(failing) = undefined;
572 \\
486 \\pub fn main() void {573 \\pub fn main() void {
487 \\ const p = nonFailing();574 \\ const p = nonFailing();
488 \\ resume p;575 \\ resume p;
489 \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable;576 \\ const p2 = async printTrace(p);
490 \\ cancel p2;
491 \\}577 \\}
492 \\578 \\
493 \\fn nonFailing() promise->anyerror!void {579 \\fn nonFailing() anyframe->anyerror!void {
494 \\ return async<std.debug.global_allocator> failing() catch unreachable;580 \\ failing_frame = async failing();
581 \\ return &failing_frame;
495 \\}582 \\}
496 \\583 \\
497 \\async fn failing() anyerror!void {584 \\async fn failing() anyerror!void {
498 \\ suspend;585 \\ suspend;
586 \\ return second();
587 \\}
588 \\
589 \\async fn second() anyerror!void {
499 \\ return error.Fail;590 \\ return error.Fail;
500 \\}591 \\}
501 \\592 \\
502 \\async fn printTrace(p: promise->anyerror!void) void {593 \\async fn printTrace(p: anyframe->anyerror!void) void {
503 \\ (await p) catch unreachable;594 \\ (await p) catch unreachable;
504 \\}595 \\}
505 );596 );
test/stage1/behavior.zig+6-7
...@@ -3,12 +3,13 @@ comptime {...@@ -3,12 +3,13 @@ comptime {
3 _ = @import("behavior/alignof.zig");3 _ = @import("behavior/alignof.zig");
4 _ = @import("behavior/array.zig");4 _ = @import("behavior/array.zig");
5 _ = @import("behavior/asm.zig");5 _ = @import("behavior/asm.zig");
6 _ = @import("behavior/async_fn.zig");
6 _ = @import("behavior/atomics.zig");7 _ = @import("behavior/atomics.zig");
8 _ = @import("behavior/await_struct.zig");
7 _ = @import("behavior/bit_shifting.zig");9 _ = @import("behavior/bit_shifting.zig");
8 _ = @import("behavior/bitcast.zig");10 _ = @import("behavior/bitcast.zig");
9 _ = @import("behavior/bitreverse.zig");11 _ = @import("behavior/bitreverse.zig");
10 _ = @import("behavior/bool.zig");12 _ = @import("behavior/bool.zig");
11 _ = @import("behavior/byteswap.zig");
12 _ = @import("behavior/bugs/1025.zig");13 _ = @import("behavior/bugs/1025.zig");
13 _ = @import("behavior/bugs/1076.zig");14 _ = @import("behavior/bugs/1076.zig");
14 _ = @import("behavior/bugs/1111.zig");15 _ = @import("behavior/bugs/1111.zig");
...@@ -38,23 +39,23 @@ comptime {...@@ -38,23 +39,23 @@ comptime {
38 _ = @import("behavior/bugs/726.zig");39 _ = @import("behavior/bugs/726.zig");
39 _ = @import("behavior/bugs/828.zig");40 _ = @import("behavior/bugs/828.zig");
40 _ = @import("behavior/bugs/920.zig");41 _ = @import("behavior/bugs/920.zig");
42 _ = @import("behavior/byteswap.zig");
41 _ = @import("behavior/byval_arg_var.zig");43 _ = @import("behavior/byval_arg_var.zig");
42 _ = @import("behavior/cancel.zig");
43 _ = @import("behavior/cast.zig");44 _ = @import("behavior/cast.zig");
44 _ = @import("behavior/const_slice_child.zig");45 _ = @import("behavior/const_slice_child.zig");
45 _ = @import("behavior/coroutine_await_struct.zig");
46 _ = @import("behavior/coroutines.zig");
47 _ = @import("behavior/defer.zig");46 _ = @import("behavior/defer.zig");
48 _ = @import("behavior/enum.zig");47 _ = @import("behavior/enum.zig");
49 _ = @import("behavior/enum_with_members.zig");48 _ = @import("behavior/enum_with_members.zig");
50 _ = @import("behavior/error.zig");49 _ = @import("behavior/error.zig");
51 _ = @import("behavior/eval.zig");50 _ = @import("behavior/eval.zig");
52 _ = @import("behavior/field_parent_ptr.zig");51 _ = @import("behavior/field_parent_ptr.zig");
52 _ = @import("behavior/floatop.zig");
53 _ = @import("behavior/fn.zig");53 _ = @import("behavior/fn.zig");
54 _ = @import("behavior/fn_in_struct_in_comptime.zig");54 _ = @import("behavior/fn_in_struct_in_comptime.zig");
55 _ = @import("behavior/for.zig");55 _ = @import("behavior/for.zig");
56 _ = @import("behavior/generics.zig");56 _ = @import("behavior/generics.zig");
57 _ = @import("behavior/hasdecl.zig");57 _ = @import("behavior/hasdecl.zig");
58 _ = @import("behavior/hasfield.zig");
58 _ = @import("behavior/if.zig");59 _ = @import("behavior/if.zig");
59 _ = @import("behavior/import.zig");60 _ = @import("behavior/import.zig");
60 _ = @import("behavior/incomplete_struct_param_tld.zig");61 _ = @import("behavior/incomplete_struct_param_tld.zig");
...@@ -63,14 +64,13 @@ comptime {...@@ -63,14 +64,13 @@ comptime {
63 _ = @import("behavior/math.zig");64 _ = @import("behavior/math.zig");
64 _ = @import("behavior/merge_error_sets.zig");65 _ = @import("behavior/merge_error_sets.zig");
65 _ = @import("behavior/misc.zig");66 _ = @import("behavior/misc.zig");
67 _ = @import("behavior/muladd.zig");
66 _ = @import("behavior/namespace_depends_on_compile_var.zig");68 _ = @import("behavior/namespace_depends_on_compile_var.zig");
67 _ = @import("behavior/new_stack_call.zig");69 _ = @import("behavior/new_stack_call.zig");
68 _ = @import("behavior/null.zig");70 _ = @import("behavior/null.zig");
69 _ = @import("behavior/optional.zig");71 _ = @import("behavior/optional.zig");
70 _ = @import("behavior/pointers.zig");72 _ = @import("behavior/pointers.zig");
71 _ = @import("behavior/popcount.zig");73 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
74 _ = @import("behavior/ptrcast.zig");74 _ = @import("behavior/ptrcast.zig");
75 _ = @import("behavior/pub_enum.zig");75 _ = @import("behavior/pub_enum.zig");
76 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");76 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
...@@ -99,5 +99,4 @@ comptime {...@@ -99,5 +99,4 @@ comptime {
99 _ = @import("behavior/void.zig");99 _ = @import("behavior/void.zig");
100 _ = @import("behavior/while.zig");100 _ = @import("behavior/while.zig");
101 _ = @import("behavior/widening.zig");101 _ = @import("behavior/widening.zig");
102 _ = @import("behavior/hasfield.zig");
103}102}
test/stage1/behavior/align.zig+62
...@@ -228,3 +228,65 @@ test "alignment of extern() void" {...@@ -228,3 +228,65 @@ test "alignment of extern() void" {
228}228}
229229
230extern fn nothing() void {}230extern fn nothing() void {}
231
232test "return error union with 128-bit integer" {
233 expect(3 == try give());
234}
235fn give() anyerror!u128 {
236 return 3;
237}
238
239test "alignment of >= 128-bit integer type" {
240 expect(@alignOf(u128) == 16);
241 expect(@alignOf(u129) == 16);
242}
243
244test "alignment of struct with 128-bit field" {
245 expect(@alignOf(struct {
246 x: u128,
247 }) == 16);
248
249 comptime {
250 expect(@alignOf(struct {
251 x: u128,
252 }) == 16);
253 }
254}
255
256test "size of extern struct with 128-bit field" {
257 expect(@sizeOf(extern struct {
258 x: u128,
259 y: u8,
260 }) == 32);
261
262 comptime {
263 expect(@sizeOf(extern struct {
264 x: u128,
265 y: u8,
266 }) == 32);
267 }
268}
269
270const DefaultAligned = struct {
271 nevermind: u32,
272 badguy: i128,
273};
274
275test "read 128-bit field from default aligned struct in stack memory" {
276 var default_aligned = DefaultAligned{
277 .nevermind = 1,
278 .badguy = 12,
279 };
280 expect((@ptrToInt(&default_aligned.badguy) % 16) == 0);
281 expect(12 == default_aligned.badguy);
282}
283
284var default_aligned_global = DefaultAligned{
285 .nevermind = 1,
286 .badguy = 12,
287};
288
289test "read 128-bit field from default aligned struct in global memory" {
290 expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0);
291 expect(12 == default_aligned_global.badguy);
292}
test/stage1/behavior/async_fn.zig created+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" {...@@ -508,7 +508,7 @@ test "peer type resolution: unreachable, null, slice" {
508}508}
509509
510test "peer type resolution: unreachable, error set, unreachable" {510test "peer type resolution: unreachable, error set, unreachable" {
511 const Error = error {511 const Error = error{
512 FileDescriptorAlreadyPresentInSet,512 FileDescriptorAlreadyPresentInSet,
513 OperationCausesCircularLoop,513 OperationCausesCircularLoop,
514 FileDescriptorNotRegistered,514 FileDescriptorNotRegistered,
...@@ -529,3 +529,8 @@ test "peer type resolution: unreachable, error set, unreachable" {...@@ -529,3 +529,8 @@ test "peer type resolution: unreachable, error set, unreachable" {
529 };529 };
530 expect(transformed_err == error.SystemResources);530 expect(transformed_err == error.SystemResources);
531}531}
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" {...@@ -982,3 +982,14 @@ test "enum literal casting to tagged union" {
982 else => @panic("fail"),982 else => @panic("fail"),
983 }983 }
984}984}
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 {...@@ -31,4 +31,4 @@ fn testMulAdd() void {
31 // var c: f128 = 6.25;31 // var c: f128 = 6.25;
32 // expect(@mulAdd(f128, a, b, c) == 20);32 // expect(@mulAdd(f128, a, b, c) == 20);
33 //}33 //}
34}
\ No newline at end of file
34}
test/stage1/behavior/type_info.zig+20-17
...@@ -116,21 +116,6 @@ fn testOptional() void {...@@ -116,21 +116,6 @@ fn testOptional() void {
116 expect(null_info.Optional.child == void);116 expect(null_info.Optional.child == void);
117}117}
118118
119test "type info: promise info" {
120 testPromise();
121 comptime testPromise();
122}
123
124fn testPromise() void {
125 const null_promise_info = @typeInfo(promise);
126 expect(TypeId(null_promise_info) == TypeId.Promise);
127 expect(null_promise_info.Promise.child == null);
128
129 const promise_info = @typeInfo(promise->usize);
130 expect(TypeId(promise_info) == TypeId.Promise);
131 expect(promise_info.Promise.child.? == usize);
132}
133
134test "type info: error set, error union info" {119test "type info: error set, error union info" {
135 testErrorSet();120 testErrorSet();
136 comptime testErrorSet();121 comptime testErrorSet();
...@@ -192,7 +177,7 @@ fn testUnion() void {...@@ -192,7 +177,7 @@ fn testUnion() void {
192 expect(TypeId(typeinfo_info) == TypeId.Union);177 expect(TypeId(typeinfo_info) == TypeId.Union);
193 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);178 expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
194 expect(typeinfo_info.Union.tag_type.? == TypeId);179 expect(typeinfo_info.Union.tag_type.? == TypeId);
195 expect(typeinfo_info.Union.fields.len == 25);180 expect(typeinfo_info.Union.fields.len == 26);
196 expect(typeinfo_info.Union.fields[4].enum_field != null);181 expect(typeinfo_info.Union.fields[4].enum_field != null);
197 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);182 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
198 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));183 expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
...@@ -265,7 +250,6 @@ fn testFunction() void {...@@ -265,7 +250,6 @@ fn testFunction() void {
265 expect(fn_info.Fn.args.len == 2);250 expect(fn_info.Fn.args.len == 2);
266 expect(fn_info.Fn.is_var_args);251 expect(fn_info.Fn.is_var_args);
267 expect(fn_info.Fn.return_type == null);252 expect(fn_info.Fn.return_type == null);
268 expect(fn_info.Fn.async_allocator_type == null);
269253
270 const test_instance: TestStruct = undefined;254 const test_instance: TestStruct = undefined;
271 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));255 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
...@@ -296,6 +280,25 @@ fn testVector() void {...@@ -296,6 +280,25 @@ fn testVector() void {
296 expect(vec_info.Vector.child == i32);280 expect(vec_info.Vector.child == i32);
297}281}
298282
283test "type info: anyframe and anyframe->T" {
284 testAnyFrame();
285 comptime testAnyFrame();
286}
287
288fn testAnyFrame() void {
289 {
290 const anyframe_info = @typeInfo(anyframe->i32);
291 expect(TypeId(anyframe_info) == .AnyFrame);
292 expect(anyframe_info.AnyFrame.child.? == i32);
293 }
294
295 {
296 const anyframe_info = @typeInfo(anyframe);
297 expect(TypeId(anyframe_info) == .AnyFrame);
298 expect(anyframe_info.AnyFrame.child == null);
299 }
300}
301
299test "type info: optional field unwrapping" {302test "type info: optional field unwrapping" {
300 const Struct = struct {303 const Struct = struct {
301 cdOffset: u32,304 cdOffset: u32,
tools/process_headers.zig+3
...@@ -504,6 +504,9 @@ const Contents = struct {...@@ -504,6 +504,9 @@ const Contents = struct {
504 }504 }
505};505};
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}
507const HashToContents = std.AutoHashMap([]const u8, Contents);510const HashToContents = std.AutoHashMap([]const u8, Contents);
508const TargetToHash = std.HashMap(DestTarget, []const u8, DestTarget.hash, DestTarget.eql);511const TargetToHash = std.HashMap(DestTarget, []const u8, DestTarget.hash, DestTarget.eql);
509const PathTable = std.AutoHashMap([]const u8, *TargetToHash);512const PathTable = std.AutoHashMap([]const u8, *TargetToHash);