authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 22:25:15-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 22:25:15-05:00
loga217c764db0a1dae539c3b243ebc329350485eb5
tree3e10e675ba5830d7da3e3fe7264ce9f3b2ca17de
parent4955c4b8f99bc45ad9aacb13de691614c4e0ad38
parent7d494b3e7b09403358232dc61f45374d6c26905f

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


22 files changed, 3270 insertions(+), 237 deletions(-)

doc/langref.html.in+118-22
......@@ -2782,30 +2782,96 @@ test "fn reflection" {
27822782 {#header_close#}
27832783 {#header_close#}
27842784 {#header_open|Errors#}
2785 {#header_open|Error Set Type#}
27852786 <p>
2786 One of the distinguishing features of Zig is its exception handling strategy.
2787 An error set is like an {#link|enum#}.
2788 However, each error name across the entire compilation gets assigned an unsigned integer
2789 greater than 0. You are allowed to declare the same error name more than once, and if you do, it
2790 gets assigned the same integer value.
27872791 </p>
27882792 <p>
2789 TODO rewrite the errors section to take into account error sets
2793 The number of unique error values across the entire compilation should determine the size of the error set type.
2794 However right now it is hard coded to be a <code>u16</code>. See <a href="https://github.com/zig-lang/zig/issues/786">#768</a>.
27902795 </p>
27912796 <p>
2792 These error values are assigned an unsigned integer value greater than 0 at
2793 compile time. You are allowed to declare the same error value more than once,
2794 and if you do, it gets assigned the same integer value.
2797 You can implicitly cast an error from a subset to its superset:
27952798 </p>
2799 {#code_begin|test#}
2800const std = @import("std");
2801
2802const FileOpenError = error {
2803 AccessDenied,
2804 OutOfMemory,
2805 FileNotFound,
2806};
2807
2808const AllocationError = error {
2809 OutOfMemory,
2810};
2811
2812test "implicit cast subset to superset" {
2813 const err = foo(AllocationError.OutOfMemory);
2814 std.debug.assert(err == FileOpenError.OutOfMemory);
2815}
2816
2817fn foo(err: AllocationError) FileOpenError {
2818 return err;
2819}
2820 {#code_end#}
2821 <p>
2822 But you cannot implicitly cast an error from a superset to a subset:
2823 </p>
2824 {#code_begin|test_err|not a member of destination error set#}
2825const FileOpenError = error {
2826 AccessDenied,
2827 OutOfMemory,
2828 FileNotFound,
2829};
2830
2831const AllocationError = error {
2832 OutOfMemory,
2833};
2834
2835test "implicit cast superset to subset" {
2836 foo(FileOpenError.OutOfMemory) catch {};
2837}
2838
2839fn foo(err: FileOpenError) AllocationError {
2840 return err;
2841}
2842 {#code_end#}
2843 <p>
2844 There is a shortcut for declaring an error set with only 1 value, and then getting that value:
2845 </p>
2846 {#code_begin|syntax#}
2847const err = error.FileNotFound;
2848 {#code_end#}
2849 <p>This is equivalent to:</p>
2850 {#code_begin|syntax#}
2851const err = (error {FileNotFound}).FileNotFound;
2852 {#code_end#}
27962853 <p>
2797 You can refer to these error values with the error namespace such as
2798 <code>error.FileNotFound</code>.
2854 This becomes useful when using {#link|Inferred Error Sets#}.
2855 </p>
2856 {#header_open|The Global Error Set#}
2857 <p><code>error</code> refers to the global error set.
2858 This is the error set that contains all errors in the entire compilation unit.
2859 It is a superset of all other error sets and a subset of none of them.
27992860 </p>
28002861 <p>
2801 Each error value across the entire compilation unit gets a unique integer,
2802 and this determines the size of the error set type.
2862 You can implicitly cast any error set to the global one, and you can explicitly
2863 cast an error of global error set to a non-global one. This inserts a language-level
2864 assert to make sure the error value is in fact in the destination error set.
28032865 </p>
28042866 <p>
2805 The error set type is one of the error values, and in the same way that pointers
2806 cannot be null, a error set instance is always an error.
2867 The global error set should generally be avoided when possible, because it prevents
2868 the compiler from knowing what errors are possible at compile-time. Knowing
2869 the error set at compile-time is better for generated documentationt and for
2870 helpful error messages such as forgetting a possible error value in a {#link|switch#}.
28072871 </p>
2808 {#code_begin|syntax#}const pure_error = error.FileNotFound;{#code_end#}
2872 {#header_close#}
2873 {#header_close#}
2874 {#header_open|Error Union Type#}
28092875 <p>
28102876 Most of the time you will not find yourself using an error set type. Instead,
28112877 likely you will be using the error union type. This is when you take an error set
......@@ -2918,7 +2984,6 @@ fn doAThing(str: []u8) !void {
29182984 a panic in Debug and ReleaseSafe modes and undefined behavior in ReleaseFast mode. So, while we're debugging the
29192985 application, if there <em>was</em> a surprise error here, the application would crash
29202986 appropriately.
2921 TODO: mention error return traces
29222987 </p>
29232988 <p>
29242989 Finally, you may want to take a different action for every situation. For that, we combine
......@@ -2986,7 +3051,7 @@ fn createFoo(param: i32) !Foo {
29863051 </li>
29873052 </ul>
29883053 {#see_also|defer|if|switch#}
2989 {#header_open|Error Union Type#}
3054
29903055 <p>An error union is created with the <code>!</code> binary operator.
29913056 You can use compile-time reflection to access the child type of an error union:</p>
29923057 {#code_begin|test#}
......@@ -3008,8 +3073,12 @@ test "error union" {
30083073 comptime assert(@typeOf(foo).ErrorSet == error);
30093074}
30103075 {#code_end#}
3076 <p>TODO the <code>||</code> operator for error sets</p>
3077 {#header_open|Inferred Error Sets#}
3078 <p>TODO</p>
30113079 {#header_close#}
3012 {#header_open|Error Set Type#}
3080 {#header_close#}
3081 {#header_open|Error Return Traces#}
30133082 <p>TODO</p>
30143083 {#header_close#}
30153084 {#header_close#}
......@@ -3775,6 +3844,25 @@ pub fn main() void {
37753844 {#header_open|@ArgType#}
37763845 <p>TODO</p>
37773846 {#header_close#}
3847 {#header_open|@atomicRmw#}
3848 <pre><code class="zig">@atomicRmw(comptime T: type, ptr: &amp;T, comptime op: builtin.AtomicRmwOp, operand: T, comptime ordering: builtin.AtomicOrder) -&gt; T</code></pre>
3849 <p>
3850 This builtin function atomically modifies memory and then returns the previous value.
3851 </p>
3852 <p>
3853 <code>T</code> must be a pointer type, a <code>bool</code>,
3854 or an integer whose bit count meets these requirements:
3855 </p>
3856 <ul>
3857 <li>At least 8</li>
3858 <li>At most the same as usize</li>
3859 <li>Power of 2</li>
3860 </ul>
3861 <p>
3862 TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
3863 we can remove this restriction
3864 </p>
3865 {#header_close#}
37783866 {#header_open|@bitCast#}
37793867 <pre><code class="zig">@bitCast(comptime DestType: type, value: var) -&gt; DestType</code></pre>
37803868 <p>
......@@ -5645,7 +5733,7 @@ UseDecl = "use" Expression ";"
56455733
56465734ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
56475735
5648FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
5736FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
56495737
56505738FnDef = option("inline" | "export") FnProto Block
56515739
......@@ -5663,7 +5751,7 @@ ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
56635751
56645752BlockOrExpression = Block | Expression
56655753
5666Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression
5754Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
56675755
56685756AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
56695757
......@@ -5687,7 +5775,7 @@ AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | Un
56875775
56885776AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "&lt;&lt;=" | "&gt;&gt;=" | "&amp;=" | "^=" | "|=" | "*%=" | "+%=" | "-%="
56895777
5690BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)
5778BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body)
56915779
56925780CompTimeExpression(body) = "comptime" body
56935781
......@@ -5705,12 +5793,20 @@ ReturnExpression = "return" option(Expression)
57055793
57065794TryExpression = "try" Expression
57075795
5796AwaitExpression = "await" Expression
5797
57085798BreakExpression = "break" option(":" Symbol) option(Expression)
57095799
5800CancelExpression = "cancel" Expression;
5801
5802ResumeExpression = "resume" Expression;
5803
57105804Defer(body) = ("defer" | "deferror") body
57115805
57125806IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))
57135807
5808SuspendExpression(body) = "suspend" option(("|" Symbol "|" body))
5809
57145810IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body)
57155811
57165812TestExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body option("else" BlockExpression(body))
......@@ -5745,7 +5841,7 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
57455841
57465842PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
57475843
5748SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
5844SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
57495845
57505846FieldAccessExpression = "." Symbol
57515847
......@@ -5761,7 +5857,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
57615857
57625858StructLiteralField = "." Symbol "=" Expression
57635859
5764PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
5860PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
57655861
57665862PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
57675863
......@@ -5769,7 +5865,7 @@ ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":"
57695865
57705866GroupedExpression = "(" Expression ")"
57715867
5772KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
5868KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
57735869
57745870ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
57755871
......@@ -5853,7 +5949,7 @@ hljs.registerLanguage("zig", function(t) {
58535949 a = t.IR + "\\s*\\(",
58545950 c = {
58555951 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
5856 built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate",
5952 built_in: "breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchg fence divExact truncate atomicRmw",
58575953 literal: "true false null undefined"
58585954 },
58595955 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+210
......@@ -56,6 +56,16 @@ struct IrExecutable {
5656 IrAnalyze *analysis;
5757 Scope *begin_scope;
5858 ZigList<Tld *> tld_list;
59
60 IrInstruction *coro_handle;
61 IrInstruction *coro_awaiter_field_ptr; // this one is shared and in the promise
62 IrInstruction *coro_result_ptr_field_ptr;
63 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
64 IrBasicBlock *coro_early_final;
65 IrBasicBlock *coro_normal_final;
66 IrBasicBlock *coro_suspend_block;
67 IrBasicBlock *coro_final_cleanup_block;
68 VariableTableEntry *coro_allocator_var;
5969};
6070
6171enum OutType {
......@@ -393,6 +403,10 @@ enum NodeType {
393403 NodeTypeIfErrorExpr,
394404 NodeTypeTestExpr,
395405 NodeTypeErrorSetDecl,
406 NodeTypeCancel,
407 NodeTypeResume,
408 NodeTypeAwaitExpr,
409 NodeTypeSuspend,
396410};
397411
398412struct AstNodeRoot {
......@@ -405,6 +419,7 @@ enum CallingConvention {
405419 CallingConventionCold,
406420 CallingConventionNaked,
407421 CallingConventionStdcall,
422 CallingConventionAsync,
408423};
409424
410425struct AstNodeFnProto {
......@@ -426,6 +441,7 @@ struct AstNodeFnProto {
426441 AstNode *section_expr;
427442
428443 bool auto_err_set;
444 AstNode *async_allocator_type;
429445};
430446
431447struct AstNodeFnDef {
......@@ -567,6 +583,8 @@ struct AstNodeFnCallExpr {
567583 AstNode *fn_ref_expr;
568584 ZigList<AstNode *> params;
569585 bool is_builtin;
586 bool is_async;
587 AstNode *async_allocator;
570588};
571589
572590struct AstNodeArrayAccessExpr {
......@@ -829,6 +847,14 @@ struct AstNodeBreakExpr {
829847 AstNode *expr; // may be null
830848};
831849
850struct AstNodeCancelExpr {
851 AstNode *expr;
852};
853
854struct AstNodeResumeExpr {
855 AstNode *expr;
856};
857
832858struct AstNodeContinueExpr {
833859 Buf *name;
834860};
......@@ -843,6 +869,15 @@ struct AstNodeErrorType {
843869struct AstNodeVarLiteral {
844870};
845871
872struct AstNodeAwaitExpr {
873 AstNode *expr;
874};
875
876struct AstNodeSuspend {
877 AstNode *block;
878 AstNode *promise_symbol;
879};
880
846881struct AstNode {
847882 enum NodeType type;
848883 size_t line;
......@@ -900,6 +935,10 @@ struct AstNode {
900935 AstNodeErrorType error_type;
901936 AstNodeVarLiteral var_literal;
902937 AstNodeErrorSetDecl err_set_decl;
938 AstNodeCancelExpr cancel_expr;
939 AstNodeResumeExpr resume_expr;
940 AstNodeAwaitExpr await_expr;
941 AstNodeSuspend suspend;
903942 } data;
904943};
905944
......@@ -926,6 +965,7 @@ struct FnTypeId {
926965 bool is_var_args;
927966 CallingConvention cc;
928967 uint32_t alignment;
968 TypeTableEntry *async_allocator_type;
929969};
930970
931971uint32_t fn_type_id_hash(FnTypeId*);
......@@ -1087,6 +1127,11 @@ struct TypeTableEntryBoundFn {
10871127 TypeTableEntry *fn_type;
10881128};
10891129
1130struct TypeTableEntryPromise {
1131 // null if `promise` instead of `promise->T`
1132 TypeTableEntry *result_type;
1133};
1134
10901135enum TypeTableEntryId {
10911136 TypeTableEntryIdInvalid,
10921137 TypeTableEntryIdVar,
......@@ -1114,6 +1159,7 @@ enum TypeTableEntryId {
11141159 TypeTableEntryIdBoundFn,
11151160 TypeTableEntryIdArgTuple,
11161161 TypeTableEntryIdOpaque,
1162 TypeTableEntryIdPromise,
11171163};
11181164
11191165struct TypeTableEntry {
......@@ -1140,11 +1186,14 @@ struct TypeTableEntry {
11401186 TypeTableEntryUnion unionation;
11411187 TypeTableEntryFn fn;
11421188 TypeTableEntryBoundFn bound_fn;
1189 TypeTableEntryPromise promise;
11431190 } data;
11441191
11451192 // use these fields to make sure we don't duplicate type table entries for the same type
11461193 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
11471194 TypeTableEntry *maybe_parent;
1195 TypeTableEntry *promise_parent;
1196 TypeTableEntry *promise_frame_parent;
11481197 // If we generate a constant name value for this type, we memoize it here.
11491198 // The type of this is array
11501199 ConstExprValue *cached_const_name_val;
......@@ -1297,6 +1346,7 @@ enum BuiltinFnId {
12971346 BuiltinFnIdArgType,
12981347 BuiltinFnIdExport,
12991348 BuiltinFnIdErrorReturnTrace,
1349 BuiltinFnIdAtomicRmw,
13001350};
13011351
13021352struct BuiltinFnEntry {
......@@ -1470,6 +1520,7 @@ struct CodeGen {
14701520 TypeTableEntry *entry_u8;
14711521 TypeTableEntry *entry_u16;
14721522 TypeTableEntry *entry_u32;
1523 TypeTableEntry *entry_u29;
14731524 TypeTableEntry *entry_u64;
14741525 TypeTableEntry *entry_u128;
14751526 TypeTableEntry *entry_i8;
......@@ -1495,6 +1546,7 @@ struct CodeGen {
14951546 TypeTableEntry *entry_var;
14961547 TypeTableEntry *entry_global_error_set;
14971548 TypeTableEntry *entry_arg_tuple;
1549 TypeTableEntry *entry_promise;
14981550 } builtin_types;
14991551
15001552 EmitFileType emit_file_type;
......@@ -1581,6 +1633,18 @@ struct CodeGen {
15811633 LLVMValueRef trap_fn_val;
15821634 LLVMValueRef return_address_fn_val;
15831635 LLVMValueRef frame_address_fn_val;
1636 LLVMValueRef coro_destroy_fn_val;
1637 LLVMValueRef coro_id_fn_val;
1638 LLVMValueRef coro_alloc_fn_val;
1639 LLVMValueRef coro_size_fn_val;
1640 LLVMValueRef coro_begin_fn_val;
1641 LLVMValueRef coro_suspend_fn_val;
1642 LLVMValueRef coro_end_fn_val;
1643 LLVMValueRef coro_free_fn_val;
1644 LLVMValueRef coro_resume_fn_val;
1645 LLVMValueRef coro_save_fn_val;
1646 LLVMValueRef coro_promise_fn_val;
1647 LLVMValueRef coro_alloc_helper_fn_val;
15841648 bool error_during_imports;
15851649
15861650 const char **clang_argv;
......@@ -1803,6 +1867,19 @@ enum AtomicOrder {
18031867 AtomicOrderSeqCst,
18041868};
18051869
1870// synchronized with the code in define_builtin_compile_vars
1871enum AtomicRmwOp {
1872 AtomicRmwOp_xchg,
1873 AtomicRmwOp_add,
1874 AtomicRmwOp_sub,
1875 AtomicRmwOp_and,
1876 AtomicRmwOp_nand,
1877 AtomicRmwOp_or,
1878 AtomicRmwOp_xor,
1879 AtomicRmwOp_max,
1880 AtomicRmwOp_min,
1881};
1882
18061883// A basic block contains no branching. Branches send control flow
18071884// to another basic block.
18081885// Phi instructions must be first in a basic block.
......@@ -1939,6 +2016,22 @@ enum IrInstructionId {
19392016 IrInstructionIdExport,
19402017 IrInstructionIdErrorReturnTrace,
19412018 IrInstructionIdErrorUnion,
2019 IrInstructionIdCancel,
2020 IrInstructionIdGetImplicitAllocator,
2021 IrInstructionIdCoroId,
2022 IrInstructionIdCoroAlloc,
2023 IrInstructionIdCoroSize,
2024 IrInstructionIdCoroBegin,
2025 IrInstructionIdCoroAllocFail,
2026 IrInstructionIdCoroSuspend,
2027 IrInstructionIdCoroEnd,
2028 IrInstructionIdCoroFree,
2029 IrInstructionIdCoroResume,
2030 IrInstructionIdCoroSave,
2031 IrInstructionIdCoroPromise,
2032 IrInstructionIdCoroAllocHelper,
2033 IrInstructionIdAtomicRmw,
2034 IrInstructionIdPromiseResultType,
19422035};
19432036
19442037struct IrInstruction {
......@@ -2142,6 +2235,9 @@ struct IrInstructionCall {
21422235 bool is_comptime;
21432236 LLVMValueRef tmp_ptr;
21442237 FnInline fn_inline;
2238 bool is_async;
2239
2240 IrInstruction *async_allocator;
21452241};
21462242
21472243struct IrInstructionConst {
......@@ -2776,6 +2872,113 @@ struct IrInstructionErrorUnion {
27762872 IrInstruction *payload;
27772873};
27782874
2875struct IrInstructionCancel {
2876 IrInstruction base;
2877
2878 IrInstruction *target;
2879};
2880
2881enum ImplicitAllocatorId {
2882 ImplicitAllocatorIdArg,
2883 ImplicitAllocatorIdLocalVar,
2884};
2885
2886struct IrInstructionGetImplicitAllocator {
2887 IrInstruction base;
2888
2889 ImplicitAllocatorId id;
2890};
2891
2892struct IrInstructionCoroId {
2893 IrInstruction base;
2894
2895 IrInstruction *promise_ptr;
2896};
2897
2898struct IrInstructionCoroAlloc {
2899 IrInstruction base;
2900
2901 IrInstruction *coro_id;
2902};
2903
2904struct IrInstructionCoroSize {
2905 IrInstruction base;
2906};
2907
2908struct IrInstructionCoroBegin {
2909 IrInstruction base;
2910
2911 IrInstruction *coro_id;
2912 IrInstruction *coro_mem_ptr;
2913};
2914
2915struct IrInstructionCoroAllocFail {
2916 IrInstruction base;
2917
2918 IrInstruction *err_val;
2919};
2920
2921struct IrInstructionCoroSuspend {
2922 IrInstruction base;
2923
2924 IrInstruction *save_point;
2925 IrInstruction *is_final;
2926};
2927
2928struct IrInstructionCoroEnd {
2929 IrInstruction base;
2930};
2931
2932struct IrInstructionCoroFree {
2933 IrInstruction base;
2934
2935 IrInstruction *coro_id;
2936 IrInstruction *coro_handle;
2937};
2938
2939struct IrInstructionCoroResume {
2940 IrInstruction base;
2941
2942 IrInstruction *awaiter_handle;
2943};
2944
2945struct IrInstructionCoroSave {
2946 IrInstruction base;
2947
2948 IrInstruction *coro_handle;
2949};
2950
2951struct IrInstructionCoroPromise {
2952 IrInstruction base;
2953
2954 IrInstruction *coro_handle;
2955};
2956
2957struct IrInstructionCoroAllocHelper {
2958 IrInstruction base;
2959
2960 IrInstruction *alloc_fn;
2961 IrInstruction *coro_size;
2962};
2963
2964struct IrInstructionAtomicRmw {
2965 IrInstruction base;
2966
2967 IrInstruction *operand_type;
2968 IrInstruction *ptr;
2969 IrInstruction *op;
2970 AtomicRmwOp resolved_op;
2971 IrInstruction *operand;
2972 IrInstruction *ordering;
2973 AtomicOrder resolved_ordering;
2974};
2975
2976struct IrInstructionPromiseResultType {
2977 IrInstruction base;
2978
2979 IrInstruction *promise_type;
2980};
2981
27792982static const size_t slice_ptr_index = 0;
27802983static const size_t slice_len_index = 1;
27812984
......@@ -2785,6 +2988,13 @@ static const size_t maybe_null_index = 1;
27852988static const size_t err_union_err_index = 0;
27862989static const size_t err_union_payload_index = 1;
27872990
2991#define ASYNC_ALLOC_FIELD_NAME "allocFn"
2992#define ASYNC_FREE_FIELD_NAME "freeFn"
2993#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
2994#define RESULT_FIELD_NAME "result"
2995#define RESULT_PTR_FIELD_NAME "result_ptr"
2996
2997
27882998enum FloatMode {
27892999 FloatModeOptimized,
27903000 FloatModeStrict,
src/analyze.cpp+182-31
......@@ -230,6 +230,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
230230 case TypeTableEntryIdBlock:
231231 case TypeTableEntryIdBoundFn:
232232 case TypeTableEntryIdArgTuple:
233 case TypeTableEntryIdPromise:
233234 return true;
234235 }
235236 zig_unreachable();
......@@ -267,6 +268,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
267268 case TypeTableEntryIdBoundFn:
268269 case TypeTableEntryIdArgTuple:
269270 case TypeTableEntryIdOpaque:
271 case TypeTableEntryIdPromise:
270272 return true;
271273 }
272274 zig_unreachable();
......@@ -339,6 +341,32 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
339341 return get_int_type(g, false, bits_needed_for_unsigned(x));
340342}
341343
344TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type) {
345 if (result_type != nullptr && result_type->promise_parent != nullptr) {
346 return result_type->promise_parent;
347 } else if (result_type == nullptr && g->builtin_types.entry_promise != nullptr) {
348 return g->builtin_types.entry_promise;
349 }
350
351 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
352 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPromise);
353 entry->type_ref = u8_ptr_type->type_ref;
354 entry->zero_bits = false;
355 entry->data.promise.result_type = result_type;
356 buf_init_from_str(&entry->name, "promise");
357 if (result_type != nullptr) {
358 buf_appendf(&entry->name, "->%s", buf_ptr(&result_type->name));
359 }
360 entry->di_type = u8_ptr_type->di_type;
361
362 if (result_type != nullptr) {
363 result_type->promise_parent = entry;
364 } else if (result_type == nullptr) {
365 g->builtin_types.entry_promise = entry;
366 }
367 return entry;
368}
369
342370TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
343371 bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
344372{
......@@ -429,6 +457,23 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
429457 return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);
430458}
431459
460TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) {
461 if (return_type->promise_frame_parent != nullptr) {
462 return return_type->promise_frame_parent;
463 }
464
465 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
466 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
467 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};
468 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
469 size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1;
470 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
471 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, field_count);
472
473 return_type->promise_frame_parent = entry;
474 return entry;
475}
476
432477TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
433478 if (child_type->maybe_parent) {
434479 TypeTableEntry *entry = child_type->maybe_parent;
......@@ -447,9 +492,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
447492 if (child_type->zero_bits) {
448493 entry->type_ref = LLVMInt1Type();
449494 entry->di_type = g->builtin_types.entry_bool->di_type;
450 } else if (child_type->id == TypeTableEntryIdPointer ||
451 child_type->id == TypeTableEntryIdFn)
452 {
495 } else if (type_is_codegen_pointer(child_type)) {
453496 // this is an optimization but also is necessary for calling C
454497 // functions where all pointers are maybe pointers
455498 // function types are technically pointers
......@@ -884,6 +927,7 @@ static const char *calling_convention_name(CallingConvention cc) {
884927 case CallingConventionCold: return "coldcc";
885928 case CallingConventionNaked: return "nakedcc";
886929 case CallingConventionStdcall: return "stdcallcc";
930 case CallingConventionAsync: return "async";
887931 }
888932 zig_unreachable();
889933}
......@@ -895,6 +939,21 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
895939 case CallingConventionCold: return "coldcc ";
896940 case CallingConventionNaked: return "nakedcc ";
897941 case CallingConventionStdcall: return "stdcallcc ";
942 case CallingConventionAsync: return "async ";
943 }
944 zig_unreachable();
945}
946
947static bool calling_convention_allows_zig_types(CallingConvention cc) {
948 switch (cc) {
949 case CallingConventionUnspecified:
950 case CallingConventionAsync:
951 return true;
952 case CallingConventionC:
953 case CallingConventionCold:
954 case CallingConventionNaked:
955 case CallingConventionStdcall:
956 return false;
898957 }
899958 zig_unreachable();
900959}
......@@ -924,8 +983,13 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
924983
925984 // populate the name of the type
926985 buf_resize(&fn_type->name, 0);
927 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
928 buf_appendf(&fn_type->name, "%sfn(", cc_str);
986 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
987 buf_appendf(&fn_type->name, "async(%s) ", buf_ptr(&fn_type_id->async_allocator_type->name));
988 } else {
989 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
990 buf_appendf(&fn_type->name, "%s", cc_str);
991 }
992 buf_appendf(&fn_type->name, "fn(");
929993 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
930994 FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
931995
......@@ -953,20 +1017,23 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
9531017 if (!skip_debug_info) {
9541018 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
9551019 handle_is_ptr(fn_type_id->return_type);
956 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
957 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
958 fn_type_id->return_type->id == TypeTableEntryIdErrorSet);
1020 bool is_async = fn_type_id->cc == CallingConventionAsync;
1021 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
9591022 // +1 for maybe making the first argument the return value
960 // +1 for maybe last argument the error return trace
961 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
1023 // +1 for maybe first argument the error return trace
1024 // +2 for maybe arguments async allocator and error code pointer
1025 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(4 + fn_type_id->param_count);
9621026 // +1 because 0 is the return type and
9631027 // +1 for maybe making first arg ret val and
964 // +1 for maybe last argument the error return trace
965 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(3 + fn_type_id->param_count);
1028 // +1 for maybe first argument the error return trace
1029 // +2 for maybe arguments async allocator and error code pointer
1030 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count);
9661031 param_di_types[0] = fn_type_id->return_type->di_type;
9671032 size_t gen_param_index = 0;
9681033 TypeTableEntry *gen_return_type;
969 if (!type_has_bits(fn_type_id->return_type)) {
1034 if (is_async) {
1035 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
1036 } else if (!type_has_bits(fn_type_id->return_type)) {
9701037 gen_return_type = g->builtin_types.entry_void;
9711038 } else if (first_arg_return) {
9721039 TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
......@@ -987,6 +1054,25 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
9871054 // after the gen_param_index += 1 because 0 is the return type
9881055 param_di_types[gen_param_index] = gen_type->di_type;
9891056 }
1057 if (is_async) {
1058 {
1059 // async allocator param
1060 TypeTableEntry *gen_type = fn_type_id->async_allocator_type;
1061 gen_param_types[gen_param_index] = gen_type->type_ref;
1062 gen_param_index += 1;
1063 // after the gen_param_index += 1 because 0 is the return type
1064 param_di_types[gen_param_index] = gen_type->di_type;
1065 }
1066
1067 {
1068 // error code pointer
1069 TypeTableEntry *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
1070 gen_param_types[gen_param_index] = gen_type->type_ref;
1071 gen_param_index += 1;
1072 // after the gen_param_index += 1 because 0 is the return type
1073 param_di_types[gen_param_index] = gen_type->di_type;
1074 }
1075 }
9901076
9911077 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
9921078 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
......@@ -997,7 +1083,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
9971083 gen_param_info->src_index = i;
9981084 gen_param_info->gen_index = SIZE_MAX;
9991085
1000 ensure_complete_type(g, type_entry);
1086 type_ensure_zero_bits_known(g, type_entry);
10011087 if (type_has_bits(type_entry)) {
10021088 TypeTableEntry *gen_type;
10031089 if (handle_is_ptr(type_entry)) {
......@@ -1096,7 +1182,16 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
10961182TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
10971183 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
10981184 fn_type->is_copyable = false;
1099 buf_init_from_str(&fn_type->name, "fn(");
1185 buf_resize(&fn_type->name, 0);
1186 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
1187 const char *async_allocator_type_str = (fn_type->data.fn.fn_type_id.async_allocator_type == nullptr) ?
1188 "var" : buf_ptr(&fn_type_id->async_allocator_type->name);
1189 buf_appendf(&fn_type->name, "async(%s) ", async_allocator_type_str);
1190 } else {
1191 const char *cc_str = calling_convention_fn_type_str(fn_type->data.fn.fn_type_id.cc);
1192 buf_appendf(&fn_type->name, "%s", cc_str);
1193 }
1194 buf_appendf(&fn_type->name, "fn(");
11001195 size_t i = 0;
11011196 for (; i < fn_type_id->next_param_index; i += 1) {
11021197 const char *comma_str = (i == 0) ? "" : ",";
......@@ -1201,6 +1296,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
12011296 case TypeTableEntryIdBoundFn:
12021297 case TypeTableEntryIdArgTuple:
12031298 case TypeTableEntryIdOpaque:
1299 case TypeTableEntryIdPromise:
12041300 return false;
12051301 case TypeTableEntryIdVoid:
12061302 case TypeTableEntryIdBool:
......@@ -1217,7 +1313,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
12171313 case TypeTableEntryIdMaybe:
12181314 {
12191315 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1220 return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
1316 return type_is_codegen_pointer(child_type);
12211317 }
12221318 case TypeTableEntryIdEnum:
12231319 return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
......@@ -1241,6 +1337,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
12411337 case TypeTableEntryIdBlock:
12421338 case TypeTableEntryIdBoundFn:
12431339 case TypeTableEntryIdArgTuple:
1340 case TypeTableEntryIdPromise:
12441341 return false;
12451342 case TypeTableEntryIdOpaque:
12461343 case TypeTableEntryIdUnreachable:
......@@ -1312,7 +1409,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13121409 bool param_is_var_args = param_node->data.param_decl.is_var_args;
13131410
13141411 if (param_is_comptime) {
1315 if (fn_type_id.cc != CallingConventionUnspecified) {
1412 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
13161413 add_node_error(g, param_node,
13171414 buf_sprintf("comptime parameter not allowed in function with calling convention '%s'",
13181415 calling_convention_name(fn_type_id.cc)));
......@@ -1323,7 +1420,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13231420 if (fn_type_id.cc == CallingConventionC) {
13241421 fn_type_id.param_count = fn_type_id.next_param_index;
13251422 continue;
1326 } else if (fn_type_id.cc == CallingConventionUnspecified) {
1423 } else if (calling_convention_allows_zig_types(fn_type_id.cc)) {
13271424 return get_generic_fn_type(g, &fn_type_id);
13281425 } else {
13291426 add_node_error(g, param_node,
......@@ -1337,7 +1434,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13371434 if (type_is_invalid(type_entry)) {
13381435 return g->builtin_types.entry_invalid;
13391436 }
1340 if (fn_type_id.cc != CallingConventionUnspecified) {
1437 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
13411438 type_ensure_zero_bits_known(g, type_entry);
13421439 if (!type_has_bits(type_entry)) {
13431440 add_node_error(g, param_node->data.param_decl.type,
......@@ -1347,7 +1444,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13471444 }
13481445 }
13491446
1350 if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, type_entry)) {
1447 if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, type_entry)) {
13511448 add_node_error(g, param_node->data.param_decl.type,
13521449 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
13531450 buf_ptr(&type_entry->name),
......@@ -1367,7 +1464,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13671464 buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
13681465 return g->builtin_types.entry_invalid;
13691466 case TypeTableEntryIdVar:
1370 if (fn_type_id.cc != CallingConventionUnspecified) {
1467 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
13711468 add_node_error(g, param_node->data.param_decl.type,
13721469 buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
13731470 calling_convention_name(fn_type_id.cc)));
......@@ -1381,7 +1478,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13811478 case TypeTableEntryIdBoundFn:
13821479 case TypeTableEntryIdMetaType:
13831480 add_node_error(g, param_node->data.param_decl.type,
1384 buf_sprintf("parameter of type '%s' must be declared inline",
1481 buf_sprintf("parameter of type '%s' must be declared comptime",
13851482 buf_ptr(&type_entry->name)));
13861483 return g->builtin_types.entry_invalid;
13871484 case TypeTableEntryIdVoid:
......@@ -1397,8 +1494,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
13971494 case TypeTableEntryIdEnum:
13981495 case TypeTableEntryIdUnion:
13991496 case TypeTableEntryIdFn:
1497 case TypeTableEntryIdPromise:
14001498 ensure_complete_type(g, type_entry);
1401 if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) {
1499 if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
14021500 add_node_error(g, param_node->data.param_decl.type,
14031501 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
14041502 return g->builtin_types.entry_invalid;
......@@ -1429,7 +1527,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14291527 fn_type_id.return_type = specified_return_type;
14301528 }
14311529
1432 if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) {
1530 if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, fn_type_id.return_type)) {
14331531 add_node_error(g, fn_proto->return_type,
14341532 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
14351533 buf_ptr(&fn_type_id.return_type->name),
......@@ -1456,7 +1554,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14561554 case TypeTableEntryIdBoundFn:
14571555 case TypeTableEntryIdVar:
14581556 case TypeTableEntryIdMetaType:
1459 if (fn_type_id.cc != CallingConventionUnspecified) {
1557 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
14601558 add_node_error(g, fn_proto->return_type,
14611559 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
14621560 buf_ptr(&fn_type_id.return_type->name),
......@@ -1478,9 +1576,20 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14781576 case TypeTableEntryIdEnum:
14791577 case TypeTableEntryIdUnion:
14801578 case TypeTableEntryIdFn:
1579 case TypeTableEntryIdPromise:
14811580 break;
14821581 }
14831582
1583 if (fn_type_id.cc == CallingConventionAsync) {
1584 if (fn_proto->async_allocator_type == nullptr) {
1585 return get_generic_fn_type(g, &fn_type_id);
1586 }
1587 fn_type_id.async_allocator_type = analyze_type_expr(g, child_scope, fn_proto->async_allocator_type);
1588 if (type_is_invalid(fn_type_id.async_allocator_type)) {
1589 return g->builtin_types.entry_invalid;
1590 }
1591 }
1592
14841593 return get_fn_type(g, &fn_type_id);
14851594}
14861595
......@@ -1615,6 +1724,8 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
16151724 field->src_index = i;
16161725 field->gen_index = i;
16171726
1727 assert(type_has_bits(field->type_entry));
1728
16181729 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
16191730 assert(prev_entry == nullptr);
16201731 }
......@@ -2129,6 +2240,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
21292240
21302241 if (enum_type->data.enumeration.zero_bits_loop_flag) {
21312242 enum_type->data.enumeration.zero_bits_known = true;
2243 enum_type->data.enumeration.zero_bits_loop_flag = false;
21322244 return;
21332245 }
21342246
......@@ -2283,6 +2395,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
22832395 // the alignment is pointer width, then assert that the first field is within that
22842396 // alignment
22852397 struct_type->data.structure.zero_bits_known = true;
2398 struct_type->data.structure.zero_bits_loop_flag = false;
22862399 if (struct_type->data.structure.abi_alignment == 0) {
22872400 if (struct_type->data.structure.layout == ContainerLayoutPacked) {
22882401 struct_type->data.structure.abi_alignment = 1;
......@@ -3117,6 +3230,10 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
31173230 case NodeTypeIfErrorExpr:
31183231 case NodeTypeTestExpr:
31193232 case NodeTypeErrorSetDecl:
3233 case NodeTypeCancel:
3234 case NodeTypeResume:
3235 case NodeTypeAwaitExpr:
3236 case NodeTypeSuspend:
31203237 zig_unreachable();
31213238 }
31223239}
......@@ -3172,6 +3289,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
31723289 case TypeTableEntryIdUnion:
31733290 case TypeTableEntryIdFn:
31743291 case TypeTableEntryIdBoundFn:
3292 case TypeTableEntryIdPromise:
31753293 return type_entry;
31763294 }
31773295 zig_unreachable();
......@@ -3550,6 +3668,7 @@ static bool is_container(TypeTableEntry *type_entry) {
35503668 case TypeTableEntryIdBoundFn:
35513669 case TypeTableEntryIdArgTuple:
35523670 case TypeTableEntryIdOpaque:
3671 case TypeTableEntryIdPromise:
35533672 return false;
35543673 }
35553674 zig_unreachable();
......@@ -3600,6 +3719,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
36003719 case TypeTableEntryIdVar:
36013720 case TypeTableEntryIdArgTuple:
36023721 case TypeTableEntryIdOpaque:
3722 case TypeTableEntryIdPromise:
36033723 zig_unreachable();
36043724 }
36053725}
......@@ -3607,15 +3727,17 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
36073727TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {
36083728 if (type->id == TypeTableEntryIdPointer) return type;
36093729 if (type->id == TypeTableEntryIdFn) return type;
3730 if (type->id == TypeTableEntryIdPromise) return type;
36103731 if (type->id == TypeTableEntryIdMaybe) {
36113732 if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
36123733 if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
3734 if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
36133735 }
36143736 return nullptr;
36153737}
36163738
36173739bool type_is_codegen_pointer(TypeTableEntry *type) {
3618 return get_codegen_ptr_type(type) != nullptr;
3740 return get_codegen_ptr_type(type) == type;
36193741}
36203742
36213743uint32_t get_ptr_align(TypeTableEntry *type) {
......@@ -3624,6 +3746,8 @@ uint32_t get_ptr_align(TypeTableEntry *type) {
36243746 return ptr_type->data.pointer.alignment;
36253747 } else if (ptr_type->id == TypeTableEntryIdFn) {
36263748 return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment;
3749 } else if (ptr_type->id == TypeTableEntryIdPromise) {
3750 return 1;
36273751 } else {
36283752 zig_unreachable();
36293753 }
......@@ -3638,7 +3762,7 @@ AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) {
36383762 return nullptr;
36393763}
36403764
3641void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars) {
3765static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars) {
36423766 TypeTableEntry *fn_type = fn_table_entry->type_entry;
36433767 assert(!fn_type->data.fn.is_generic);
36443768 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
......@@ -3659,7 +3783,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
36593783 TypeTableEntry *param_type = param_info->type;
36603784 bool is_noalias = param_info->is_noalias;
36613785
3662 if (is_noalias && !type_is_codegen_pointer(param_type)) {
3786 if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
36633787 add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
36643788 }
36653789
......@@ -4092,6 +4216,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
40924216 case TypeTableEntryIdErrorSet:
40934217 case TypeTableEntryIdFn:
40944218 case TypeTableEntryIdEnum:
4219 case TypeTableEntryIdPromise:
40954220 return false;
40964221 case TypeTableEntryIdArray:
40974222 case TypeTableEntryIdStruct:
......@@ -4100,8 +4225,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
41004225 return type_has_bits(type_entry->data.error_union.payload_type);
41014226 case TypeTableEntryIdMaybe:
41024227 return type_has_bits(type_entry->data.maybe.child_type) &&
4103 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
4104 type_entry->data.maybe.child_type->id != TypeTableEntryIdFn;
4228 !type_is_codegen_pointer(type_entry->data.maybe.child_type);
41054229 case TypeTableEntryIdUnion:
41064230 assert(type_entry->data.unionation.complete);
41074231 if (type_entry->data.unionation.gen_field_count == 0)
......@@ -4203,6 +4327,7 @@ uint32_t fn_type_id_hash(FnTypeId *id) {
42034327 result += ((uint32_t)(id->cc)) * (uint32_t)3349388391;
42044328 result += id->is_var_args ? (uint32_t)1931444534 : 0;
42054329 result += hash_ptr(id->return_type);
4330 result += hash_ptr(id->async_allocator_type);
42064331 result += id->alignment * 0xd3b3f3e2;
42074332 for (size_t i = 0; i < id->param_count; i += 1) {
42084333 FnTypeParamInfo *info = &id->param_info[i];
......@@ -4217,7 +4342,8 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
42174342 a->return_type != b->return_type ||
42184343 a->is_var_args != b->is_var_args ||
42194344 a->param_count != b->param_count ||
4220 a->alignment != b->alignment)
4345 a->alignment != b->alignment ||
4346 a->async_allocator_type != b->async_allocator_type)
42214347 {
42224348 return false;
42234349 }
......@@ -4339,6 +4465,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
43394465 }
43404466 zig_unreachable();
43414467 }
4468 case TypeTableEntryIdPromise:
4469 // TODO better hashing algorithm
4470 return 223048345;
43424471 case TypeTableEntryIdUndefLit:
43434472 return 162837799;
43444473 case TypeTableEntryIdNullLit:
......@@ -4498,6 +4627,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
44984627 case TypeTableEntryIdPointer:
44994628 case TypeTableEntryIdVoid:
45004629 case TypeTableEntryIdUnreachable:
4630 case TypeTableEntryIdPromise:
45014631 return false;
45024632 }
45034633 zig_unreachable();
......@@ -4967,6 +5097,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
49675097 case TypeTableEntryIdInvalid:
49685098 case TypeTableEntryIdUnreachable:
49695099 case TypeTableEntryIdVar:
5100 case TypeTableEntryIdPromise:
49705101 zig_unreachable();
49715102 }
49725103 zig_unreachable();
......@@ -5241,6 +5372,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
52415372 buf_appendf(buf, "(args value)");
52425373 return;
52435374 }
5375 case TypeTableEntryIdPromise:
5376 zig_unreachable();
52445377 }
52455378 zig_unreachable();
52465379}
......@@ -5302,6 +5435,7 @@ uint32_t type_id_hash(TypeId x) {
53025435 case TypeTableEntryIdBlock:
53035436 case TypeTableEntryIdBoundFn:
53045437 case TypeTableEntryIdArgTuple:
5438 case TypeTableEntryIdPromise:
53055439 zig_unreachable();
53065440 case TypeTableEntryIdErrorUnion:
53075441 return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
......@@ -5339,6 +5473,7 @@ bool type_id_eql(TypeId a, TypeId b) {
53395473 case TypeTableEntryIdUndefLit:
53405474 case TypeTableEntryIdNullLit:
53415475 case TypeTableEntryIdMaybe:
5476 case TypeTableEntryIdPromise:
53425477 case TypeTableEntryIdErrorSet:
53435478 case TypeTableEntryIdEnum:
53445479 case TypeTableEntryIdUnion:
......@@ -5466,6 +5601,7 @@ static const TypeTableEntryId all_type_ids[] = {
54665601 TypeTableEntryIdBoundFn,
54675602 TypeTableEntryIdArgTuple,
54685603 TypeTableEntryIdOpaque,
5604 TypeTableEntryIdPromise,
54695605};
54705606
54715607TypeTableEntryId type_id_at_index(size_t index) {
......@@ -5530,6 +5666,8 @@ size_t type_id_index(TypeTableEntryId id) {
55305666 return 22;
55315667 case TypeTableEntryIdOpaque:
55325668 return 23;
5669 case TypeTableEntryIdPromise:
5670 return 24;
55335671 }
55345672 zig_unreachable();
55355673}
......@@ -5587,6 +5725,8 @@ const char *type_id_name(TypeTableEntryId id) {
55875725 return "ArgTuple";
55885726 case TypeTableEntryIdOpaque:
55895727 return "Opaque";
5728 case TypeTableEntryIdPromise:
5729 return "Promise";
55905730 }
55915731 zig_unreachable();
55925732}
......@@ -5669,3 +5809,14 @@ bool type_is_global_error_set(TypeTableEntry *err_set_type) {
56695809 assert(err_set_type->data.error_set.infer_fn == nullptr);
56705810 return err_set_type->data.error_set.err_count == UINT32_MAX;
56715811}
5812
5813uint32_t get_coro_frame_align_bytes(CodeGen *g) {
5814 return g->pointer_size_bytes * 2;
5815}
5816
5817bool fn_type_can_fail(FnTypeId *fn_type_id) {
5818 TypeTableEntry *return_type = fn_type_id->return_type;
5819 return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||
5820 fn_type_id->cc == CallingConventionAsync;
5821}
5822
src/analyze.hpp+6-1
......@@ -35,6 +35,8 @@ TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
3535TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);
3636TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
3737 TypeTableEntry *field_types[], size_t field_count);
38TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type);
39TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type);
3840TypeTableEntry *get_test_fn_type(CodeGen *g);
3941bool handle_is_ptr(TypeTableEntry *type_entry);
4042void find_libc_include_path(CodeGen *g);
......@@ -50,6 +52,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
5052Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
5153void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
5254bool type_is_codegen_pointer(TypeTableEntry *type);
55
5356TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type);
5457uint32_t get_ptr_align(TypeTableEntry *type);
5558TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
......@@ -92,7 +95,6 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
9295void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max);
9396
9497void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
95void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);
9698void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node);
9799
98100ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
......@@ -190,4 +192,7 @@ void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
190192
191193TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
192194
195uint32_t get_coro_frame_align_bytes(CodeGen *g);
196bool fn_type_can_fail(FnTypeId *fn_type_id);
197
193198#endif
src/ast_render.cpp+37
......@@ -244,6 +244,14 @@ static const char *node_type_str(NodeType node_type) {
244244 return "TestExpr";
245245 case NodeTypeErrorSetDecl:
246246 return "ErrorSetDecl";
247 case NodeTypeCancel:
248 return "Cancel";
249 case NodeTypeResume:
250 return "Resume";
251 case NodeTypeAwaitExpr:
252 return "AwaitExpr";
253 case NodeTypeSuspend:
254 return "Suspend";
247255 }
248256 zig_unreachable();
249257}
......@@ -1037,6 +1045,35 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
10371045 fprintf(ar->f, "}");
10381046 break;
10391047 }
1048 case NodeTypeCancel:
1049 {
1050 fprintf(ar->f, "cancel ");
1051 render_node_grouped(ar, node->data.cancel_expr.expr);
1052 break;
1053 }
1054 case NodeTypeResume:
1055 {
1056 fprintf(ar->f, "resume ");
1057 render_node_grouped(ar, node->data.resume_expr.expr);
1058 break;
1059 }
1060 case NodeTypeAwaitExpr:
1061 {
1062 fprintf(ar->f, "await ");
1063 render_node_grouped(ar, node->data.await_expr.expr);
1064 break;
1065 }
1066 case NodeTypeSuspend:
1067 {
1068 fprintf(ar->f, "suspend");
1069 if (node->data.suspend.block != nullptr) {
1070 fprintf(ar->f, " |");
1071 render_node_grouped(ar, node->data.suspend.promise_symbol);
1072 fprintf(ar->f, "| ");
1073 render_node_grouped(ar, node->data.suspend.block);
1074 }
1075 break;
1076 }
10401077 case NodeTypeFnDecl:
10411078 case NodeTypeParamDecl:
10421079 case NodeTypeTestDecl:
src/codegen.cpp+572-17
......@@ -381,6 +381,8 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
381381 } else {
382382 return LLVMCCallConv;
383383 }
384 case CallingConventionAsync:
385 return LLVMFastCallConv;
384386 }
385387 zig_unreachable();
386388}
......@@ -410,10 +412,10 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
410412 return UINT32_MAX;
411413 }
412414 TypeTableEntry *fn_type = fn_table_entry->type_entry;
413 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
414 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) {
415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
415416 return UINT32_MAX;
416417 }
418 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
417419 bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
418420 return first_arg_ret ? 1 : 0;
419421}
......@@ -540,7 +542,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
540542
541543 if (!type_has_bits(return_type)) {
542544 // nothing to do
543 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {
545 } else if (type_is_codegen_pointer(return_type)) {
544546 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
545547 } else if (handle_is_ptr(return_type) &&
546548 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
......@@ -925,6 +927,177 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
925927 return g->memcpy_fn_val;
926928}
927929
930static LLVMValueRef get_coro_destroy_fn_val(CodeGen *g) {
931 if (g->coro_destroy_fn_val)
932 return g->coro_destroy_fn_val;
933
934 LLVMTypeRef param_types[] = {
935 LLVMPointerType(LLVMInt8Type(), 0),
936 };
937 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
938 Buf *name = buf_sprintf("llvm.coro.destroy");
939 g->coro_destroy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
940 assert(LLVMGetIntrinsicID(g->coro_destroy_fn_val));
941
942 return g->coro_destroy_fn_val;
943}
944
945static LLVMValueRef get_coro_id_fn_val(CodeGen *g) {
946 if (g->coro_id_fn_val)
947 return g->coro_id_fn_val;
948
949 LLVMTypeRef param_types[] = {
950 LLVMInt32Type(),
951 LLVMPointerType(LLVMInt8Type(), 0),
952 LLVMPointerType(LLVMInt8Type(), 0),
953 LLVMPointerType(LLVMInt8Type(), 0),
954 };
955 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 4, false);
956 Buf *name = buf_sprintf("llvm.coro.id");
957 g->coro_id_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
958 assert(LLVMGetIntrinsicID(g->coro_id_fn_val));
959
960 return g->coro_id_fn_val;
961}
962
963static LLVMValueRef get_coro_alloc_fn_val(CodeGen *g) {
964 if (g->coro_alloc_fn_val)
965 return g->coro_alloc_fn_val;
966
967 LLVMTypeRef param_types[] = {
968 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
969 };
970 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 1, false);
971 Buf *name = buf_sprintf("llvm.coro.alloc");
972 g->coro_alloc_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
973 assert(LLVMGetIntrinsicID(g->coro_alloc_fn_val));
974
975 return g->coro_alloc_fn_val;
976}
977
978static LLVMValueRef get_coro_size_fn_val(CodeGen *g) {
979 if (g->coro_size_fn_val)
980 return g->coro_size_fn_val;
981
982 LLVMTypeRef fn_type = LLVMFunctionType(g->builtin_types.entry_usize->type_ref, nullptr, 0, false);
983 Buf *name = buf_sprintf("llvm.coro.size.i%d", g->pointer_size_bytes * 8);
984 g->coro_size_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
985 assert(LLVMGetIntrinsicID(g->coro_size_fn_val));
986
987 return g->coro_size_fn_val;
988}
989
990static LLVMValueRef get_coro_begin_fn_val(CodeGen *g) {
991 if (g->coro_begin_fn_val)
992 return g->coro_begin_fn_val;
993
994 LLVMTypeRef param_types[] = {
995 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
996 LLVMPointerType(LLVMInt8Type(), 0),
997 };
998 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
999 Buf *name = buf_sprintf("llvm.coro.begin");
1000 g->coro_begin_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1001 assert(LLVMGetIntrinsicID(g->coro_begin_fn_val));
1002
1003 return g->coro_begin_fn_val;
1004}
1005
1006static LLVMValueRef get_coro_suspend_fn_val(CodeGen *g) {
1007 if (g->coro_suspend_fn_val)
1008 return g->coro_suspend_fn_val;
1009
1010 LLVMTypeRef param_types[] = {
1011 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1012 LLVMInt1Type(),
1013 };
1014 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt8Type(), param_types, 2, false);
1015 Buf *name = buf_sprintf("llvm.coro.suspend");
1016 g->coro_suspend_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1017 assert(LLVMGetIntrinsicID(g->coro_suspend_fn_val));
1018
1019 return g->coro_suspend_fn_val;
1020}
1021
1022static LLVMValueRef get_coro_end_fn_val(CodeGen *g) {
1023 if (g->coro_end_fn_val)
1024 return g->coro_end_fn_val;
1025
1026 LLVMTypeRef param_types[] = {
1027 LLVMPointerType(LLVMInt8Type(), 0),
1028 LLVMInt1Type(),
1029 };
1030 LLVMTypeRef fn_type = LLVMFunctionType(LLVMInt1Type(), param_types, 2, false);
1031 Buf *name = buf_sprintf("llvm.coro.end");
1032 g->coro_end_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1033 assert(LLVMGetIntrinsicID(g->coro_end_fn_val));
1034
1035 return g->coro_end_fn_val;
1036}
1037
1038static LLVMValueRef get_coro_free_fn_val(CodeGen *g) {
1039 if (g->coro_free_fn_val)
1040 return g->coro_free_fn_val;
1041
1042 LLVMTypeRef param_types[] = {
1043 ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()),
1044 LLVMPointerType(LLVMInt8Type(), 0),
1045 };
1046 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 2, false);
1047 Buf *name = buf_sprintf("llvm.coro.free");
1048 g->coro_free_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1049 assert(LLVMGetIntrinsicID(g->coro_free_fn_val));
1050
1051 return g->coro_free_fn_val;
1052}
1053
1054static LLVMValueRef get_coro_resume_fn_val(CodeGen *g) {
1055 if (g->coro_resume_fn_val)
1056 return g->coro_resume_fn_val;
1057
1058 LLVMTypeRef param_types[] = {
1059 LLVMPointerType(LLVMInt8Type(), 0),
1060 };
1061 LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 1, false);
1062 Buf *name = buf_sprintf("llvm.coro.resume");
1063 g->coro_resume_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1064 assert(LLVMGetIntrinsicID(g->coro_resume_fn_val));
1065
1066 return g->coro_resume_fn_val;
1067}
1068
1069static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
1070 if (g->coro_save_fn_val)
1071 return g->coro_save_fn_val;
1072
1073 LLVMTypeRef param_types[] = {
1074 LLVMPointerType(LLVMInt8Type(), 0),
1075 };
1076 LLVMTypeRef fn_type = LLVMFunctionType(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()), param_types, 1, false);
1077 Buf *name = buf_sprintf("llvm.coro.save");
1078 g->coro_save_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1079 assert(LLVMGetIntrinsicID(g->coro_save_fn_val));
1080
1081 return g->coro_save_fn_val;
1082}
1083
1084static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1085 if (g->coro_promise_fn_val)
1086 return g->coro_promise_fn_val;
1087
1088 LLVMTypeRef param_types[] = {
1089 LLVMPointerType(LLVMInt8Type(), 0),
1090 LLVMInt32Type(),
1091 LLVMInt1Type(),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1094 Buf *name = buf_sprintf("llvm.coro.promise");
1095 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1097
1098 return g->coro_promise_fn_val;
1099}
1100
9281101static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
9291102 if (g->return_address_fn_val)
9301103 return g->return_address_fn_val;
......@@ -2506,6 +2679,25 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
25062679 }
25072680}
25082681
2682static bool get_prefix_arg_err_ret_stack(CodeGen *g, FnTypeId *fn_type_id) {
2683 return g->have_err_ret_tracing &&
2684 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
2685 fn_type_id->return_type->id == TypeTableEntryIdErrorSet ||
2686 fn_type_id->cc == CallingConventionAsync);
2687}
2688
2689static size_t get_async_allocator_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
2690 // 0 1 2 3
2691 // err_ret_stack allocator_ptr err_code other_args...
2692 return get_prefix_arg_err_ret_stack(g, fn_type_id) ? 1 : 0;
2693}
2694
2695static size_t get_async_err_code_arg_index(CodeGen *g, FnTypeId *fn_type_id) {
2696 // 0 1 2 3
2697 // err_ret_stack allocator_ptr err_code other_args...
2698 return 1 + get_async_allocator_arg_index(g, fn_type_id);
2699}
2700
25092701static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
25102702 LLVMValueRef fn_val;
25112703 TypeTableEntry *fn_type;
......@@ -2519,11 +2711,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
25192711 }
25202712
25212713 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
2714
25222715 TypeTableEntry *src_return_type = fn_type_id->return_type;
25232716 bool ret_has_bits = type_has_bits(src_return_type);
2524 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
2525 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet);
2526 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
2717
2718 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
2719 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc);
2720 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
2721 // +2 for the async args
2722 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2;
25272723 bool is_var_args = fn_type_id->is_var_args;
25282724 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
25292725 size_t gen_param_index = 0;
......@@ -2535,6 +2731,14 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
25352731 gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;
25362732 gen_param_index += 1;
25372733 }
2734 if (instruction->is_async) {
2735 gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator);
2736 gen_param_index += 1;
2737
2738 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
2739 gen_param_values[gen_param_index] = err_val_ptr;
2740 gen_param_index += 1;
2741 }
25382742 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
25392743 IrInstruction *param_instruction = instruction->args[call_i];
25402744 TypeTableEntry *param_type = param_instruction->value.type;
......@@ -2572,6 +2776,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
25722776 }
25732777 }
25742778
2779 if (instruction->is_async) {
2780 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
2781 LLVMBuildStore(g->builder, result, payload_ptr);
2782 return instruction->tmp_ptr;
2783 }
2784
25752785 if (src_return_type->id == TypeTableEntryIdUnreachable) {
25762786 return LLVMBuildUnreachable(g->builder);
25772787 } else if (!ret_has_bits) {
......@@ -2783,7 +2993,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLV
27832993 if (child_type->zero_bits) {
27842994 return maybe_handle;
27852995 } else {
2786 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
2996 bool maybe_is_ptr = type_is_codegen_pointer(child_type);
27872997 if (maybe_is_ptr) {
27882998 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
27892999 } else {
......@@ -2823,7 +3033,7 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
28233033 if (child_type->zero_bits) {
28243034 return nullptr;
28253035 } else {
2826 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
3036 bool maybe_is_ptr = type_is_codegen_pointer(child_type);
28273037 if (maybe_is_ptr) {
28283038 return maybe_ptr;
28293039 } else {
......@@ -3046,6 +3256,10 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
30463256 {
30473257 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
30483258 ptr_val = target_val;
3259 } else if (target_type->id == TypeTableEntryIdMaybe &&
3260 target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
3261 {
3262 zig_panic("TODO audit this function");
30493263 } else if (target_type->id == TypeTableEntryIdStruct && target_type->data.structure.is_slice) {
30503264 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
30513265 align_bytes = slice_ptr_type->data.pointer.alignment;
......@@ -3088,6 +3302,20 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
30883302 return g->cur_err_ret_trace_val;
30893303}
30903304
3305static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
3306 LLVMValueRef target_handle = ir_llvm_value(g, instruction->target);
3307 LLVMBuildCall(g->builder, get_coro_destroy_fn_val(g), &target_handle, 1, "");
3308 return nullptr;
3309}
3310
3311static LLVMValueRef ir_render_get_implicit_allocator(CodeGen *g, IrExecutable *executable,
3312 IrInstructionGetImplicitAllocator *instruction)
3313{
3314 assert(instruction->id == ImplicitAllocatorIdArg);
3315 size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
3316 return LLVMGetParam(g->cur_fn_val, allocator_arg_index);
3317}
3318
30913319static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
30923320 switch (atomic_order) {
30933321 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
......@@ -3100,6 +3328,23 @@ static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
31003328 zig_unreachable();
31013329}
31023330
3331static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) {
3332 switch (op) {
3333 case AtomicRmwOp_xchg: return LLVMAtomicRMWBinOpXchg;
3334 case AtomicRmwOp_add: return LLVMAtomicRMWBinOpAdd;
3335 case AtomicRmwOp_sub: return LLVMAtomicRMWBinOpSub;
3336 case AtomicRmwOp_and: return LLVMAtomicRMWBinOpAnd;
3337 case AtomicRmwOp_nand: return LLVMAtomicRMWBinOpNand;
3338 case AtomicRmwOp_or: return LLVMAtomicRMWBinOpOr;
3339 case AtomicRmwOp_xor: return LLVMAtomicRMWBinOpXor;
3340 case AtomicRmwOp_max:
3341 return is_signed ? LLVMAtomicRMWBinOpMax : LLVMAtomicRMWBinOpUMax;
3342 case AtomicRmwOp_min:
3343 return is_signed ? LLVMAtomicRMWBinOpMin : LLVMAtomicRMWBinOpUMin;
3344 }
3345 zig_unreachable();
3346}
3347
31033348static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
31043349 LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
31053350 LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
......@@ -3508,9 +3753,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
35083753 }
35093754
35103755 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
3511 if (child_type->id == TypeTableEntryIdPointer ||
3512 child_type->id == TypeTableEntryIdFn)
3513 {
3756 if (type_is_codegen_pointer(child_type)) {
35143757 return payload_val;
35153758 }
35163759
......@@ -3682,6 +3925,264 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
36823925 return nullptr;
36833926}
36843927
3928static LLVMValueRef ir_render_coro_id(CodeGen *g, IrExecutable *executable, IrInstructionCoroId *instruction) {
3929 LLVMValueRef promise_ptr = ir_llvm_value(g, instruction->promise_ptr);
3930 LLVMValueRef align_val = LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false);
3931 LLVMValueRef null = LLVMConstIntToPtr(LLVMConstNull(g->builtin_types.entry_usize->type_ref),
3932 LLVMPointerType(LLVMInt8Type(), 0));
3933 LLVMValueRef params[] = {
3934 align_val,
3935 promise_ptr,
3936 null,
3937 null,
3938 };
3939 return LLVMBuildCall(g->builder, get_coro_id_fn_val(g), params, 4, "");
3940}
3941
3942static LLVMValueRef ir_render_coro_alloc(CodeGen *g, IrExecutable *executable, IrInstructionCoroAlloc *instruction) {
3943 LLVMValueRef token = ir_llvm_value(g, instruction->coro_id);
3944 return LLVMBuildCall(g->builder, get_coro_alloc_fn_val(g), &token, 1, "");
3945}
3946
3947static LLVMValueRef ir_render_coro_size(CodeGen *g, IrExecutable *executable, IrInstructionCoroSize *instruction) {
3948 return LLVMBuildCall(g->builder, get_coro_size_fn_val(g), nullptr, 0, "");
3949}
3950
3951static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, IrInstructionCoroBegin *instruction) {
3952 LLVMValueRef coro_id = ir_llvm_value(g, instruction->coro_id);
3953 LLVMValueRef coro_mem_ptr = ir_llvm_value(g, instruction->coro_mem_ptr);
3954 LLVMValueRef params[] = {
3955 coro_id,
3956 coro_mem_ptr,
3957 };
3958 return LLVMBuildCall(g->builder, get_coro_begin_fn_val(g), params, 2, "");
3959}
3960
3961static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executable,
3962 IrInstructionCoroAllocFail *instruction)
3963{
3964 size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
3965 LLVMValueRef err_code_ptr_val = LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index);
3966 LLVMValueRef err_code = ir_llvm_value(g, instruction->err_val);
3967 LLVMBuildStore(g->builder, err_code, err_code_ptr_val);
3968
3969 LLVMValueRef return_value;
3970 if (ir_want_runtime_safety(g, &instruction->base)) {
3971 return_value = LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0));
3972 } else {
3973 return_value = LLVMGetUndef(LLVMPointerType(LLVMInt8Type(), 0));
3974 }
3975 LLVMBuildRet(g->builder, return_value);
3976 return nullptr;
3977}
3978
3979static LLVMValueRef ir_render_coro_suspend(CodeGen *g, IrExecutable *executable, IrInstructionCoroSuspend *instruction) {
3980 LLVMValueRef save_point;
3981 if (instruction->save_point == nullptr) {
3982 save_point = LLVMConstNull(ZigLLVMTokenTypeInContext(LLVMGetGlobalContext()));
3983 } else {
3984 save_point = ir_llvm_value(g, instruction->save_point);
3985 }
3986 LLVMValueRef is_final = ir_llvm_value(g, instruction->is_final);
3987 LLVMValueRef params[] = {
3988 save_point,
3989 is_final,
3990 };
3991 return LLVMBuildCall(g->builder, get_coro_suspend_fn_val(g), params, 2, "");
3992}
3993
3994static LLVMValueRef ir_render_coro_end(CodeGen *g, IrExecutable *executable, IrInstructionCoroEnd *instruction) {
3995 LLVMValueRef params[] = {
3996 LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)),
3997 LLVMConstNull(LLVMInt1Type()),
3998 };
3999 return LLVMBuildCall(g->builder, get_coro_end_fn_val(g), params, 2, "");
4000}
4001
4002static LLVMValueRef ir_render_coro_free(CodeGen *g, IrExecutable *executable, IrInstructionCoroFree *instruction) {
4003 LLVMValueRef coro_id = ir_llvm_value(g, instruction->coro_id);
4004 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
4005 LLVMValueRef params[] = {
4006 coro_id,
4007 coro_handle,
4008 };
4009 return LLVMBuildCall(g->builder, get_coro_free_fn_val(g), params, 2, "");
4010}
4011
4012static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, IrInstructionCoroResume *instruction) {
4013 LLVMValueRef awaiter_handle = ir_llvm_value(g, instruction->awaiter_handle);
4014 return LLVMBuildCall(g->builder, get_coro_resume_fn_val(g), &awaiter_handle, 1, "");
4015}
4016
4017static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, IrInstructionCoroSave *instruction) {
4018 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
4019 return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");
4020}
4021
4022static LLVMValueRef ir_render_coro_promise(CodeGen *g, IrExecutable *executable, IrInstructionCoroPromise *instruction) {
4023 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
4024 LLVMValueRef params[] = {
4025 coro_handle,
4026 LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false),
4027 LLVMConstNull(LLVMInt1Type()),
4028 };
4029 LLVMValueRef uncasted_result = LLVMBuildCall(g->builder, get_coro_promise_fn_val(g), params, 3, "");
4030 return LLVMBuildBitCast(g->builder, uncasted_result, instruction->base.value.type->type_ref, "");
4031}
4032
4033static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
4034 if (g->coro_alloc_helper_fn_val != nullptr)
4035 return g->coro_alloc_helper_fn_val;
4036
4037 assert(fn_type->id == TypeTableEntryIdFn);
4038
4039 TypeTableEntry *ptr_to_err_code_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
4040
4041 LLVMTypeRef alloc_raw_fn_type_ref = LLVMGetElementType(alloc_fn_type_ref);
4042 LLVMTypeRef *alloc_fn_arg_types = allocate<LLVMTypeRef>(LLVMCountParamTypes(alloc_raw_fn_type_ref));
4043 LLVMGetParamTypes(alloc_raw_fn_type_ref, alloc_fn_arg_types);
4044
4045 ZigList<LLVMTypeRef> arg_types = {};
4046 arg_types.append(alloc_fn_type_ref);
4047 if (g->have_err_ret_tracing) {
4048 arg_types.append(alloc_fn_arg_types[1]);
4049 }
4050 arg_types.append(alloc_fn_arg_types[g->have_err_ret_tracing ? 2 : 1]);
4051 arg_types.append(ptr_to_err_code_type->type_ref);
4052 arg_types.append(g->builtin_types.entry_usize->type_ref);
4053
4054 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0),
4055 arg_types.items, arg_types.length, false);
4056
4057 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_coro_alloc_helper"), false);
4058 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
4059 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
4060 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
4061 addLLVMFnAttr(fn_val, "nounwind");
4062 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
4063 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
4064
4065 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
4066 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
4067 FnTableEntry *prev_cur_fn = g->cur_fn;
4068 LLVMValueRef prev_cur_fn_val = g->cur_fn_val;
4069
4070 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
4071 LLVMPositionBuilderAtEnd(g->builder, entry_block);
4072 ZigLLVMClearCurrentDebugLocation(g->builder);
4073 g->cur_fn = nullptr;
4074 g->cur_fn_val = fn_val;
4075
4076 LLVMValueRef sret_ptr = LLVMBuildAlloca(g->builder, LLVMGetElementType(alloc_fn_arg_types[0]), "");
4077
4078 size_t next_arg = 0;
4079 LLVMValueRef alloc_fn_val = LLVMGetParam(fn_val, next_arg);
4080 next_arg += 1;
4081
4082 LLVMValueRef stack_trace_val;
4083 if (g->have_err_ret_tracing) {
4084 stack_trace_val = LLVMGetParam(fn_val, next_arg);
4085 next_arg += 1;
4086 }
4087
4088 LLVMValueRef allocator_val = LLVMGetParam(fn_val, next_arg);
4089 next_arg += 1;
4090 LLVMValueRef err_code_ptr = LLVMGetParam(fn_val, next_arg);
4091 next_arg += 1;
4092 LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
4093 next_arg += 1;
4094 LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,
4095 get_coro_frame_align_bytes(g), false);
4096
4097 ZigList<LLVMValueRef> args = {};
4098 args.append(sret_ptr);
4099 if (g->have_err_ret_tracing) {
4100 args.append(stack_trace_val);
4101 }
4102 args.append(allocator_val);
4103 args.append(coro_size);
4104 args.append(alignment_val);
4105 ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length,
4106 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4107 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");
4108 LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
4109 LLVMBuildStore(g->builder, err_val, err_code_ptr);
4110 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, LLVMConstNull(LLVMTypeOf(err_val)), "");
4111 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "AllocOk");
4112 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "AllocFail");
4113 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
4114
4115 LLVMPositionBuilderAtEnd(g->builder, ok_block);
4116 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
4117 TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
4118 TypeTableEntry *slice_type = get_slice_type(g, u8_ptr_type);
4119 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
4120 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
4121 LLVMValueRef ptr_val = LLVMBuildLoad(g->builder, ptr_field_ptr, "");
4122 LLVMBuildRet(g->builder, ptr_val);
4123
4124 LLVMPositionBuilderAtEnd(g->builder, fail_block);
4125 LLVMBuildRet(g->builder, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)));
4126
4127 g->cur_fn = prev_cur_fn;
4128 g->cur_fn_val = prev_cur_fn_val;
4129 LLVMPositionBuilderAtEnd(g->builder, prev_block);
4130 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
4131
4132 g->coro_alloc_helper_fn_val = fn_val;
4133 return fn_val;
4134}
4135
4136static LLVMValueRef ir_render_coro_alloc_helper(CodeGen *g, IrExecutable *executable,
4137 IrInstructionCoroAllocHelper *instruction)
4138{
4139 LLVMValueRef alloc_fn = ir_llvm_value(g, instruction->alloc_fn);
4140 LLVMValueRef coro_size = ir_llvm_value(g, instruction->coro_size);
4141 LLVMValueRef fn_val = get_coro_alloc_helper_fn_val(g, LLVMTypeOf(alloc_fn), instruction->alloc_fn->value.type);
4142 size_t err_code_ptr_arg_index = get_async_err_code_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
4143 size_t allocator_arg_index = get_async_allocator_arg_index(g, &g->cur_fn->type_entry->data.fn.fn_type_id);
4144
4145 ZigList<LLVMValueRef> params = {};
4146 params.append(alloc_fn);
4147 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, g->cur_fn);
4148 if (err_ret_trace_arg_index != UINT32_MAX) {
4149 params.append(LLVMGetParam(g->cur_fn_val, err_ret_trace_arg_index));
4150 }
4151 params.append(LLVMGetParam(g->cur_fn_val, allocator_arg_index));
4152 params.append(LLVMGetParam(g->cur_fn_val, err_code_ptr_arg_index));
4153 params.append(coro_size);
4154
4155 return ZigLLVMBuildCall(g->builder, fn_val, params.items, params.length,
4156 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4157}
4158
4159static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4160 IrInstructionAtomicRmw *instruction)
4161{
4162 bool is_signed;
4163 TypeTableEntry *operand_type = instruction->operand->value.type;
4164 if (operand_type->id == TypeTableEntryIdInt) {
4165 is_signed = operand_type->data.integral.is_signed;
4166 } else {
4167 is_signed = false;
4168 }
4169 LLVMAtomicRMWBinOp op = to_LLVMAtomicRMWBinOp(instruction->resolved_op, is_signed);
4170 LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->resolved_ordering);
4171 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
4172 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
4173
4174 if (get_codegen_ptr_type(operand_type) == nullptr) {
4175 return LLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, false);
4176 }
4177
4178 // it's a pointer but we need to treat it as an int
4179 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
4180 LLVMPointerType(g->builtin_types.entry_usize->type_ref, 0), "");
4181 LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_usize->type_ref, "");
4182 LLVMValueRef uncasted_result = LLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering, false);
4183 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
4184}
4185
36854186static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
36864187 AstNode *source_node = instruction->source_node;
36874188 Scope *scope = instruction->scope;
......@@ -3745,7 +4246,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
37454246 case IrInstructionIdTagType:
37464247 case IrInstructionIdExport:
37474248 case IrInstructionIdErrorUnion:
4249 case IrInstructionIdPromiseResultType:
37484250 zig_unreachable();
4251
37494252 case IrInstructionIdReturn:
37504253 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
37514254 case IrInstructionIdDeclVar:
......@@ -3862,12 +4365,43 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
38624365 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
38634366 case IrInstructionIdErrorReturnTrace:
38644367 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
4368 case IrInstructionIdCancel:
4369 return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction);
4370 case IrInstructionIdGetImplicitAllocator:
4371 return ir_render_get_implicit_allocator(g, executable, (IrInstructionGetImplicitAllocator *)instruction);
4372 case IrInstructionIdCoroId:
4373 return ir_render_coro_id(g, executable, (IrInstructionCoroId *)instruction);
4374 case IrInstructionIdCoroAlloc:
4375 return ir_render_coro_alloc(g, executable, (IrInstructionCoroAlloc *)instruction);
4376 case IrInstructionIdCoroSize:
4377 return ir_render_coro_size(g, executable, (IrInstructionCoroSize *)instruction);
4378 case IrInstructionIdCoroBegin:
4379 return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);
4380 case IrInstructionIdCoroAllocFail:
4381 return ir_render_coro_alloc_fail(g, executable, (IrInstructionCoroAllocFail *)instruction);
4382 case IrInstructionIdCoroSuspend:
4383 return ir_render_coro_suspend(g, executable, (IrInstructionCoroSuspend *)instruction);
4384 case IrInstructionIdCoroEnd:
4385 return ir_render_coro_end(g, executable, (IrInstructionCoroEnd *)instruction);
4386 case IrInstructionIdCoroFree:
4387 return ir_render_coro_free(g, executable, (IrInstructionCoroFree *)instruction);
4388 case IrInstructionIdCoroResume:
4389 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
4390 case IrInstructionIdCoroSave:
4391 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
4392 case IrInstructionIdCoroPromise:
4393 return ir_render_coro_promise(g, executable, (IrInstructionCoroPromise *)instruction);
4394 case IrInstructionIdCoroAllocHelper:
4395 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4396 case IrInstructionIdAtomicRmw:
4397 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
38654398 }
38664399 zig_unreachable();
38674400}
38684401
38694402static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
38704403 assert(fn_entry);
4404
38714405 IrExecutable *executable = &fn_entry->analyzed_executable;
38724406 assert(executable->basic_block_list.length > 0);
38734407 for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
......@@ -4009,6 +4543,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
40094543 case TypeTableEntryIdPointer:
40104544 case TypeTableEntryIdFn:
40114545 case TypeTableEntryIdMaybe:
4546 case TypeTableEntryIdPromise:
40124547 {
40134548 LLVMValueRef ptr_val = gen_const_val(g, const_val, "");
40144549 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
......@@ -4104,9 +4639,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
41044639 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
41054640 if (child_type->zero_bits) {
41064641 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
4107 } else if (child_type->id == TypeTableEntryIdPointer ||
4108 child_type->id == TypeTableEntryIdFn)
4109 {
4642 } else if (type_is_codegen_pointer(child_type)) {
41104643 if (const_val->data.x_maybe) {
41114644 return gen_const_val(g, const_val->data.x_maybe, "");
41124645 } else {
......@@ -4426,6 +4959,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
44264959 case TypeTableEntryIdVar:
44274960 case TypeTableEntryIdArgTuple:
44284961 case TypeTableEntryIdOpaque:
4962 case TypeTableEntryIdPromise:
44294963 zig_unreachable();
44304964
44314965 }
......@@ -5235,6 +5769,7 @@ static void define_builtin_types(CodeGen *g) {
52355769
52365770 g->builtin_types.entry_u8 = get_int_type(g, false, 8);
52375771 g->builtin_types.entry_u16 = get_int_type(g, false, 16);
5772 g->builtin_types.entry_u29 = get_int_type(g, false, 29);
52385773 g->builtin_types.entry_u32 = get_int_type(g, false, 32);
52395774 g->builtin_types.entry_u64 = get_int_type(g, false, 64);
52405775 g->builtin_types.entry_u128 = get_int_type(g, false, 128);
......@@ -5271,6 +5806,10 @@ static void define_builtin_types(CodeGen *g) {
52715806
52725807 g->primitive_type_table.put(&entry->name, entry);
52735808 }
5809 {
5810 TypeTableEntry *entry = get_promise_type(g, nullptr);
5811 g->primitive_type_table.put(&entry->name, entry);
5812 }
52745813
52755814}
52765815
......@@ -5348,6 +5887,7 @@ static void define_builtin_fns(CodeGen *g) {
53485887 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
53495888 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
53505889 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
5890 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
53515891}
53525892
53535893static const char *bool_to_str(bool b) {
......@@ -5477,6 +6017,20 @@ static void define_builtin_compile_vars(CodeGen *g) {
54776017 " SeqCst,\n"
54786018 "};\n\n");
54796019 }
6020 {
6021 buf_appendf(contents,
6022 "pub const AtomicRmwOp = enum {\n"
6023 " Xchg,\n"
6024 " Add,\n"
6025 " Sub,\n"
6026 " And,\n"
6027 " Nand,\n"
6028 " Or,\n"
6029 " Xor,\n"
6030 " Max,\n"
6031 " Min,\n"
6032 "};\n\n");
6033 }
54806034 {
54816035 buf_appendf(contents,
54826036 "pub const Mode = enum {\n"
......@@ -5898,6 +6452,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
58986452 case TypeTableEntryIdArgTuple:
58996453 case TypeTableEntryIdErrorUnion:
59006454 case TypeTableEntryIdErrorSet:
6455 case TypeTableEntryIdPromise:
59016456 zig_unreachable();
59026457 case TypeTableEntryIdVoid:
59036458 case TypeTableEntryIdUnreachable:
......@@ -6027,9 +6582,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
60276582 if (child_type->zero_bits) {
60286583 buf_init_from_str(out_buf, "bool");
60296584 return;
6030 } else if (child_type->id == TypeTableEntryIdPointer ||
6031 child_type->id == TypeTableEntryIdFn)
6032 {
6585 } else if (type_is_codegen_pointer(child_type)) {
60336586 return get_c_type(g, gen_h, child_type, out_buf);
60346587 } else {
60356588 zig_unreachable();
......@@ -6084,6 +6637,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
60846637 case TypeTableEntryIdNullLit:
60856638 case TypeTableEntryIdVar:
60866639 case TypeTableEntryIdArgTuple:
6640 case TypeTableEntryIdPromise:
60876641 zig_unreachable();
60886642 }
60896643}
......@@ -6244,6 +6798,7 @@ static void gen_h_file(CodeGen *g) {
62446798 case TypeTableEntryIdArgTuple:
62456799 case TypeTableEntryIdMaybe:
62466800 case TypeTableEntryIdFn:
6801 case TypeTableEntryIdPromise:
62476802 zig_unreachable();
62486803 case TypeTableEntryIdEnum:
62496804 assert(type_entry->data.enumeration.layout == ContainerLayoutExtern);
src/ir.cpp+1336-85
......@@ -65,6 +65,7 @@ enum ConstCastResultId {
6565 ConstCastResultIdFnArgNoAlias,
6666 ConstCastResultIdType,
6767 ConstCastResultIdUnresolvedInferredErrSet,
68 ConstCastResultIdAsyncAllocatorType,
6869};
6970
7071struct ConstCastErrSetMismatch {
......@@ -92,6 +93,7 @@ struct ConstCastOnly {
9293 ConstCastOnly *error_union_payload;
9394 ConstCastOnly *error_union_error_set;
9495 ConstCastOnly *return_type;
96 ConstCastOnly *async_allocator_type;
9597 ConstCastArg fn_arg;
9698 ConstCastArgNoAlias arg_no_alias;
9799 } data;
......@@ -104,6 +106,10 @@ static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *ins
104106static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
105107static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
106108static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
109static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
110 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type);
111static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
112 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr);
107113
108114ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
109115 assert(const_val->type->id == TypeTableEntryIdPointer);
......@@ -637,6 +643,70 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
637643 return IrInstructionIdErrorUnion;
638644}
639645
646static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) {
647 return IrInstructionIdCancel;
648}
649
650static constexpr IrInstructionId ir_instruction_id(IrInstructionGetImplicitAllocator *) {
651 return IrInstructionIdGetImplicitAllocator;
652}
653
654static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroId *) {
655 return IrInstructionIdCoroId;
656}
657
658static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAlloc *) {
659 return IrInstructionIdCoroAlloc;
660}
661
662static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSize *) {
663 return IrInstructionIdCoroSize;
664}
665
666static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroBegin *) {
667 return IrInstructionIdCoroBegin;
668}
669
670static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *) {
671 return IrInstructionIdCoroAllocFail;
672}
673
674static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) {
675 return IrInstructionIdCoroSuspend;
676}
677
678static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) {
679 return IrInstructionIdCoroEnd;
680}
681
682static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) {
683 return IrInstructionIdCoroFree;
684}
685
686static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
687 return IrInstructionIdCoroResume;
688}
689
690static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
691 return IrInstructionIdCoroSave;
692}
693
694static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
695 return IrInstructionIdCoroPromise;
696}
697
698static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
699 return IrInstructionIdCoroAllocHelper;
700}
701
702static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
703 return IrInstructionIdAtomicRmw;
704}
705
706static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
707 return IrInstructionIdPromiseResultType;
708}
709
640710template<typename T>
641711static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
642712 T *special_instruction = allocate<T>(1);
......@@ -708,14 +778,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou
708778 return &return_instruction->base;
709779}
710780
711static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_instruction,
712 IrInstruction *return_value)
713{
714 IrInstruction *new_instruction = ir_build_return(irb, old_instruction->scope, old_instruction->source_node, return_value);
715 ir_link_new_instruction(new_instruction, old_instruction);
716 return new_instruction;
717}
718
719781static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
720782 TypeTableEntry *type_entry)
721783{
......@@ -779,6 +841,14 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, Scope *scope, AstNode
779841 return &const_instruction->base;
780842}
781843
844static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) {
845 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
846 const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8;
847 const_instruction->base.value.special = ConstValSpecialStatic;
848 bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value);
849 return &const_instruction->base;
850}
851
782852static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
783853 TypeTableEntry *type_entry)
784854{
......@@ -866,6 +936,27 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
866936 return &const_instruction->base;
867937}
868938
939static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
940 TypeTableEntry *return_type)
941{
942 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
943
944 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
945 const_instruction->base.value.type = struct_type;
946 const_instruction->base.value.special = ConstValSpecialStatic;
947 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
948 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
949 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
950 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
951 if (struct_type->data.structure.src_field_count > 1) {
952 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
953 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
954 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
955 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
956 }
957 return &const_instruction->base;
958}
959
869960static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
870961 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
871962{
......@@ -950,15 +1041,6 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As
9501041 return &instruction->base;
9511042}
9521043
953static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
954 IrInstruction *struct_ptr, TypeStructField *type_struct_field)
955{
956 IrInstruction *new_instruction = ir_build_struct_field_ptr(irb, old_instruction->scope,
957 old_instruction->source_node, struct_ptr, type_struct_field);
958 ir_link_new_instruction(new_instruction, old_instruction);
959 return new_instruction;
960}
961
9621044static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
9631045 IrInstruction *union_ptr, TypeUnionField *field)
9641046{
......@@ -982,7 +1064,7 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
9821064
9831065static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
9841066 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
985 bool is_comptime, FnInline fn_inline)
1067 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
9861068{
9871069 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
9881070 call_instruction->fn_entry = fn_entry;
......@@ -991,21 +1073,25 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
9911073 call_instruction->fn_inline = fn_inline;
9921074 call_instruction->args = args;
9931075 call_instruction->arg_count = arg_count;
1076 call_instruction->is_async = is_async;
1077 call_instruction->async_allocator = async_allocator;
9941078
9951079 if (fn_ref)
9961080 ir_ref_instruction(fn_ref, irb->current_basic_block);
9971081 for (size_t i = 0; i < arg_count; i += 1)
9981082 ir_ref_instruction(args[i], irb->current_basic_block);
1083 if (async_allocator)
1084 ir_ref_instruction(async_allocator, irb->current_basic_block);
9991085
10001086 return &call_instruction->base;
10011087}
10021088
10031089static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
10041090 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1005 bool is_comptime, FnInline fn_inline)
1091 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
10061092{
10071093 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1008 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline);
1094 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
10091095 ir_link_new_instruction(new_instruction, old_instruction);
10101096 return new_instruction;
10111097}
......@@ -2396,6 +2482,182 @@ static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode
23962482 return &instruction->base;
23972483}
23982484
2485static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node,
2486 IrInstruction *target)
2487{
2488 IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
2489 instruction->target = target;
2490
2491 ir_ref_instruction(target, irb->current_basic_block);
2492
2493 return &instruction->base;
2494}
2495
2496static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *scope, AstNode *source_node,
2497 ImplicitAllocatorId id)
2498{
2499 IrInstructionGetImplicitAllocator *instruction = ir_build_instruction<IrInstructionGetImplicitAllocator>(irb, scope, source_node);
2500 instruction->id = id;
2501
2502 return &instruction->base;
2503}
2504
2505static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) {
2506 IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);
2507 instruction->promise_ptr = promise_ptr;
2508
2509 ir_ref_instruction(promise_ptr, irb->current_basic_block);
2510
2511 return &instruction->base;
2512}
2513
2514static IrInstruction *ir_build_coro_alloc(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id) {
2515 IrInstructionCoroAlloc *instruction = ir_build_instruction<IrInstructionCoroAlloc>(irb, scope, source_node);
2516 instruction->coro_id = coro_id;
2517
2518 ir_ref_instruction(coro_id, irb->current_basic_block);
2519
2520 return &instruction->base;
2521}
2522
2523static IrInstruction *ir_build_coro_size(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2524 IrInstructionCoroSize *instruction = ir_build_instruction<IrInstructionCoroSize>(irb, scope, source_node);
2525
2526 return &instruction->base;
2527}
2528
2529static IrInstruction *ir_build_coro_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id, IrInstruction *coro_mem_ptr) {
2530 IrInstructionCoroBegin *instruction = ir_build_instruction<IrInstructionCoroBegin>(irb, scope, source_node);
2531 instruction->coro_id = coro_id;
2532 instruction->coro_mem_ptr = coro_mem_ptr;
2533
2534 ir_ref_instruction(coro_id, irb->current_basic_block);
2535 ir_ref_instruction(coro_mem_ptr, irb->current_basic_block);
2536
2537 return &instruction->base;
2538}
2539
2540static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_val) {
2541 IrInstructionCoroAllocFail *instruction = ir_build_instruction<IrInstructionCoroAllocFail>(irb, scope, source_node);
2542 instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
2543 instruction->base.value.special = ConstValSpecialStatic;
2544 instruction->err_val = err_val;
2545
2546 ir_ref_instruction(err_val, irb->current_basic_block);
2547
2548 return &instruction->base;
2549}
2550
2551static IrInstruction *ir_build_coro_suspend(IrBuilder *irb, Scope *scope, AstNode *source_node,
2552 IrInstruction *save_point, IrInstruction *is_final)
2553{
2554 IrInstructionCoroSuspend *instruction = ir_build_instruction<IrInstructionCoroSuspend>(irb, scope, source_node);
2555 instruction->save_point = save_point;
2556 instruction->is_final = is_final;
2557
2558 if (save_point != nullptr) ir_ref_instruction(save_point, irb->current_basic_block);
2559 ir_ref_instruction(is_final, irb->current_basic_block);
2560
2561 return &instruction->base;
2562}
2563
2564static IrInstruction *ir_build_coro_end(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2565 IrInstructionCoroEnd *instruction = ir_build_instruction<IrInstructionCoroEnd>(irb, scope, source_node);
2566 return &instruction->base;
2567}
2568
2569static IrInstruction *ir_build_coro_free(IrBuilder *irb, Scope *scope, AstNode *source_node,
2570 IrInstruction *coro_id, IrInstruction *coro_handle)
2571{
2572 IrInstructionCoroFree *instruction = ir_build_instruction<IrInstructionCoroFree>(irb, scope, source_node);
2573 instruction->coro_id = coro_id;
2574 instruction->coro_handle = coro_handle;
2575
2576 ir_ref_instruction(coro_id, irb->current_basic_block);
2577 ir_ref_instruction(coro_handle, irb->current_basic_block);
2578
2579 return &instruction->base;
2580}
2581
2582static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node,
2583 IrInstruction *awaiter_handle)
2584{
2585 IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node);
2586 instruction->awaiter_handle = awaiter_handle;
2587
2588 ir_ref_instruction(awaiter_handle, irb->current_basic_block);
2589
2590 return &instruction->base;
2591}
2592
2593static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *source_node,
2594 IrInstruction *coro_handle)
2595{
2596 IrInstructionCoroSave *instruction = ir_build_instruction<IrInstructionCoroSave>(irb, scope, source_node);
2597 instruction->coro_handle = coro_handle;
2598
2599 ir_ref_instruction(coro_handle, irb->current_basic_block);
2600
2601 return &instruction->base;
2602}
2603
2604static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node,
2605 IrInstruction *coro_handle)
2606{
2607 IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node);
2608 instruction->coro_handle = coro_handle;
2609
2610 ir_ref_instruction(coro_handle, irb->current_basic_block);
2611
2612 return &instruction->base;
2613}
2614
2615static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
2616 IrInstruction *alloc_fn, IrInstruction *coro_size)
2617{
2618 IrInstructionCoroAllocHelper *instruction = ir_build_instruction<IrInstructionCoroAllocHelper>(irb, scope, source_node);
2619 instruction->alloc_fn = alloc_fn;
2620 instruction->coro_size = coro_size;
2621
2622 ir_ref_instruction(alloc_fn, irb->current_basic_block);
2623 ir_ref_instruction(coro_size, irb->current_basic_block);
2624
2625 return &instruction->base;
2626}
2627
2628static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode *source_node,
2629 IrInstruction *operand_type, IrInstruction *ptr, IrInstruction *op, IrInstruction *operand,
2630 IrInstruction *ordering, AtomicRmwOp resolved_op, AtomicOrder resolved_ordering)
2631{
2632 IrInstructionAtomicRmw *instruction = ir_build_instruction<IrInstructionAtomicRmw>(irb, scope, source_node);
2633 instruction->operand_type = operand_type;
2634 instruction->ptr = ptr;
2635 instruction->op = op;
2636 instruction->operand = operand;
2637 instruction->ordering = ordering;
2638 instruction->resolved_op = resolved_op;
2639 instruction->resolved_ordering = resolved_ordering;
2640
2641 if (operand_type != nullptr) ir_ref_instruction(operand_type, irb->current_basic_block);
2642 ir_ref_instruction(ptr, irb->current_basic_block);
2643 if (op != nullptr) ir_ref_instruction(op, irb->current_basic_block);
2644 ir_ref_instruction(operand, irb->current_basic_block);
2645 if (ordering != nullptr) ir_ref_instruction(ordering, irb->current_basic_block);
2646
2647 return &instruction->base;
2648}
2649
2650static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2651 IrInstruction *promise_type)
2652{
2653 IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node);
2654 instruction->promise_type = promise_type;
2655
2656 ir_ref_instruction(promise_type, irb->current_basic_block);
2657
2658 return &instruction->base;
2659}
2660
23992661static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
24002662 results[ReturnKindUnconditional] = 0;
24012663 results[ReturnKindError] = 0;
......@@ -2468,6 +2730,36 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
24682730 return nullptr;
24692731}
24702732
2733static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
2734 bool is_generated_code)
2735{
2736 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
2737 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2738 if (!is_async) {
2739 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
2740 return_inst->is_gen = is_generated_code;
2741 return return_inst;
2742 }
2743
2744 if (irb->exec->coro_result_ptr_field_ptr) {
2745 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
2746 ir_build_store_ptr(irb, scope, node, result_ptr, return_value);
2747 }
2748 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
2749 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
2750 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
2751 IrInstruction *replacement_value = irb->exec->coro_handle;
2752 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
2753 promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
2754 AtomicRmwOp_xchg, AtomicOrderSeqCst);
2755 ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
2756 IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
2757 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
2758 return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
2759 is_comptime);
2760 // the above blocks are rendered by ir_gen after the rest of codegen
2761}
2762
24712763static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
24722764 assert(node->type == NodeTypeReturnExpr);
24732765
......@@ -2517,18 +2809,22 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
25172809 }
25182810
25192811 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
2812 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
25202813
25212814 ir_set_cursor_at_end_and_append_block(irb, err_block);
25222815 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2523 ir_build_return(irb, scope, node, return_value);
2816 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
25242817
25252818 ir_set_cursor_at_end_and_append_block(irb, ok_block);
25262819 ir_gen_defers_for_block(irb, scope, outer_scope, false);
2527 return ir_build_return(irb, scope, node, return_value);
2820 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
2821
2822 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
2823 return ir_gen_async_return(irb, scope, node, return_value, false);
25282824 } else {
25292825 // generate unconditional defers
25302826 ir_gen_defers_for_block(irb, scope, outer_scope, false);
2531 return ir_build_return(irb, scope, node, return_value);
2827 return ir_gen_async_return(irb, scope, node, return_value, false);
25322828 }
25332829 }
25342830 case ReturnKindError:
......@@ -2548,7 +2844,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
25482844 ir_set_cursor_at_end_and_append_block(irb, return_block);
25492845 ir_gen_defers_for_block(irb, scope, outer_scope, true);
25502846 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2551 ir_build_return(irb, scope, node, err_val);
2847 ir_gen_async_return(irb, scope, node, err_val, false);
25522848
25532849 ir_set_cursor_at_end_and_append_block(irb, continue_block);
25542850 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
......@@ -3739,7 +4035,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37394035 }
37404036 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
37414037
3742 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline);
4038 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
37434039 }
37444040 case BuiltinFnIdTypeId:
37454041 {
......@@ -3849,6 +4145,38 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38494145 {
38504146 return ir_build_error_return_trace(irb, scope, node);
38514147 }
4148 case BuiltinFnIdAtomicRmw:
4149 {
4150 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4151 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4152 if (arg0_value == irb->codegen->invalid_instruction)
4153 return arg0_value;
4154
4155 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4156 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4157 if (arg1_value == irb->codegen->invalid_instruction)
4158 return arg1_value;
4159
4160 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
4161 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
4162 if (arg2_value == irb->codegen->invalid_instruction)
4163 return arg2_value;
4164
4165 AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
4166 IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
4167 if (arg3_value == irb->codegen->invalid_instruction)
4168 return arg3_value;
4169
4170 AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
4171 IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
4172 if (arg4_value == irb->codegen->invalid_instruction)
4173 return arg4_value;
4174
4175 return ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value,
4176 arg4_value,
4177 // these 2 values don't mean anything since we passed non-null values for other args
4178 AtomicRmwOp_xchg, AtomicOrderMonotonic);
4179 }
38524180 }
38534181 zig_unreachable();
38544182}
......@@ -3873,7 +4201,17 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
38734201 return args[i];
38744202 }
38754203
3876 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);
4204 bool is_async = node->data.fn_call_expr.is_async;
4205 IrInstruction *async_allocator = nullptr;
4206 if (is_async) {
4207 if (node->data.fn_call_expr.async_allocator) {
4208 async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
4209 if (async_allocator == irb->codegen->invalid_instruction)
4210 return async_allocator;
4211 }
4212 }
4213
4214 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
38774215}
38784216
38794217static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
......@@ -5604,6 +5942,187 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
56045942 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
56055943}
56065944
5945static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5946 assert(node->type == NodeTypeCancel);
5947
5948 IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, parent_scope);
5949 if (target_inst == irb->codegen->invalid_instruction)
5950 return irb->codegen->invalid_instruction;
5951
5952 return ir_build_cancel(irb, parent_scope, node, target_inst);
5953}
5954
5955static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5956 assert(node->type == NodeTypeResume);
5957
5958 IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope);
5959 if (target_inst == irb->codegen->invalid_instruction)
5960 return irb->codegen->invalid_instruction;
5961
5962 return ir_build_coro_resume(irb, parent_scope, node, target_inst);
5963}
5964
5965static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
5966 assert(node->type == NodeTypeAwaitExpr);
5967
5968 IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, parent_scope);
5969 if (target_inst == irb->codegen->invalid_instruction)
5970 return irb->codegen->invalid_instruction;
5971
5972 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
5973 if (!fn_entry) {
5974 add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
5975 return irb->codegen->invalid_instruction;
5976 }
5977 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
5978 add_node_error(irb->codegen, node, buf_sprintf("await in non-async function"));
5979 return irb->codegen->invalid_instruction;
5980 }
5981
5982 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
5983 if (scope_defer_expr) {
5984 if (!scope_defer_expr->reported_err) {
5985 add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression"));
5986 scope_defer_expr->reported_err = true;
5987 }
5988 return irb->codegen->invalid_instruction;
5989 }
5990
5991 Scope *outer_scope = irb->exec->begin_scope;
5992
5993 IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, parent_scope, node, target_inst);
5994 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
5995 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
5996
5997 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
5998 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
5999 awaiter_handle_field_name);
6000
6001 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
6002 VariableTableEntry *result_var = ir_create_var(irb, node, parent_scope, nullptr,
6003 false, false, true, const_bool_false);
6004 IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node);
6005 IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst);
6006 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type);
6007 ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value);
6008 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false);
6009 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
6010 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);
6011 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node,
6012 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6013 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node,
6014 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,
6015 AtomicRmwOp_xchg, AtomicOrderSeqCst);
6016 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6017 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6018 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6019 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");
6020 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
6021
6022 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6023 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6024 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6025 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
6026 ir_build_cancel(irb, parent_scope, node, target_inst);
6027 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
6028
6029 ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
6030 IrInstruction *suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
6031 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6032 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6033
6034 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6035 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
6036 cases[0].block = resume_block;
6037 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6038 cases[1].block = cleanup_block;
6039 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6040 2, cases, const_bool_false);
6041
6042 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6043 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6044 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);
6045
6046 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6047 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
6048 ir_build_br(irb, parent_scope, node, merge_block, const_bool_false);
6049
6050 ir_set_cursor_at_end_and_append_block(irb, merge_block);
6051 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6052 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
6053 incoming_blocks[0] = resume_block;
6054 incoming_values[0] = yes_suspend_result;
6055 incoming_blocks[1] = no_suspend_block;
6056 incoming_values[1] = no_suspend_result;
6057 return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
6058}
6059
6060static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
6061 assert(node->type == NodeTypeSuspend);
6062
6063 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
6064 if (!fn_entry) {
6065 add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
6066 return irb->codegen->invalid_instruction;
6067 }
6068 if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) {
6069 add_node_error(irb->codegen, node, buf_sprintf("suspend in non-async function"));
6070 return irb->codegen->invalid_instruction;
6071 }
6072
6073 ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope);
6074 if (scope_defer_expr) {
6075 if (!scope_defer_expr->reported_err) {
6076 add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside defer expression"));
6077 scope_defer_expr->reported_err = true;
6078 }
6079 return irb->codegen->invalid_instruction;
6080 }
6081
6082 Scope *outer_scope = irb->exec->begin_scope;
6083
6084
6085 IrInstruction *suspend_code;
6086 IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false);
6087 if (node->data.suspend.block == nullptr) {
6088 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, nullptr, const_bool_false);
6089 } else {
6090 assert(node->data.suspend.promise_symbol != nullptr);
6091 assert(node->data.suspend.promise_symbol->type == NodeTypeSymbol);
6092 Buf *promise_symbol_name = node->data.suspend.promise_symbol->data.symbol_expr.symbol;
6093 Scope *child_scope;
6094 if (!buf_eql_str(promise_symbol_name, "_")) {
6095 VariableTableEntry *promise_var = ir_create_var(irb, node, parent_scope, promise_symbol_name,
6096 true, true, false, const_bool_false);
6097 ir_build_var_decl(irb, parent_scope, node, promise_var, nullptr, nullptr, irb->exec->coro_handle);
6098 child_scope = promise_var->child_scope;
6099 } else {
6100 child_scope = parent_scope;
6101 }
6102 IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
6103 ir_gen_node(irb, node->data.suspend.block, child_scope);
6104 suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false);
6105 }
6106
6107 IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup");
6108 IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume");
6109
6110 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6111 cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0);
6112 cases[0].block = resume_block;
6113 cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1);
6114 cases[1].block = cleanup_block;
6115 ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
6116 2, cases, const_bool_false);
6117
6118 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6119 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6120 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);
6121
6122 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6123 return ir_build_const_void(irb, parent_scope, node);
6124}
6125
56076126static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
56086127 LVal lval)
56096128{
......@@ -5700,6 +6219,14 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
57006219 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
57016220 case NodeTypeErrorSetDecl:
57026221 return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
6222 case NodeTypeCancel:
6223 return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
6224 case NodeTypeResume:
6225 return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval);
6226 case NodeTypeAwaitExpr:
6227 return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);
6228 case NodeTypeSuspend:
6229 return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval);
57036230 }
57046231 zig_unreachable();
57056232}
......@@ -5728,6 +6255,7 @@ static void invalidate_exec(IrExecutable *exec) {
57286255 invalidate_exec(exec->source_exec);
57296256}
57306257
6258
57316259bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {
57326260 assert(node->owner);
57336261
......@@ -5742,13 +6270,162 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
57426270 // Entry block gets a reference because we enter it to begin.
57436271 ir_ref_bb(irb->current_basic_block);
57446272
6273 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
6274 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
6275 IrInstruction *coro_id;
6276 IrInstruction *u8_ptr_type;
6277 IrInstruction *const_bool_false;
6278 IrInstruction *coro_result_field_ptr;
6279 TypeTableEntry *return_type;
6280 Buf *result_ptr_field_name;
6281 VariableTableEntry *coro_size_var;
6282 if (is_async) {
6283 // create the coro promise
6284 const_bool_false = ir_build_const_bool(irb, scope, node, false);
6285 VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6286
6287 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6288 IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type);
6289 ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init);
6290 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false);
6291
6292 VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6293 IrInstruction *null_value = ir_build_const_null(irb, scope, node);
6294 IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node,
6295 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6296 ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6297 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node,
6298 await_handle_var, false, false);
6299
6300 u8_ptr_type = ir_build_const_type(irb, scope, node,
6301 get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
6302 IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr);
6303 coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr);
6304 coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false);
6305 IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);
6306 ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size);
6307 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
6308 ImplicitAllocatorIdArg);
6309 irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false);
6310 ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
6311 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
6312 IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name);
6313 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);
6314 IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size);
6315 IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr);
6316 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");
6317 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");
6318 ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
6319
6320 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6321 IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
6322 ir_build_return(irb, scope, node, undef);
6323
6324 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
6325 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr);
6326 irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr);
6327
6328 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6329 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6330 awaiter_handle_field_name);
6331 if (type_has_bits(return_type)) {
6332 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6333 coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6334 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6335 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6336 result_ptr_field_name);
6337 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, coro_result_field_ptr);
6338 }
6339
6340
6341 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
6342 irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal");
6343 irb->exec->coro_suspend_block = ir_create_basic_block(irb, scope, "Suspend");
6344 irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
6345 }
6346
57456347 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE);
57466348 assert(result);
57476349 if (irb->exec->invalid)
57486350 return false;
57496351
57506352 if (!instr_is_unreachable(result)) {
5751 ir_mark_gen(ir_build_return(irb, scope, result->source_node, result));
6353 ir_gen_async_return(irb, scope, result->source_node, result, true);
6354 }
6355
6356 if (is_async) {
6357 IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume");
6358 IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree");
6359
6360 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final);
6361 IrInstruction *const_bool_true = ir_build_const_bool(irb, scope, node, true);
6362 IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, nullptr, const_bool_true);
6363 IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2);
6364 cases[0].value = ir_build_const_u8(irb, scope, node, 0);
6365 cases[0].block = invalid_resume_block;
6366 cases[1].value = ir_build_const_u8(irb, scope, node, 1);
6367 cases[1].block = irb->exec->coro_final_cleanup_block;
6368 ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false);
6369
6370 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
6371 ir_build_coro_end(irb, scope, node);
6372 ir_build_return(irb, scope, node, irb->exec->coro_handle);
6373
6374 ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block);
6375 ir_build_unreachable(irb, scope, node);
6376
6377 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
6378 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
6379
6380 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
6381 if (type_has_bits(return_type)) {
6382 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
6383 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr);
6384 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type,
6385 coro_result_field_ptr);
6386 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
6387 fn_entry->type_entry->data.fn.fn_type_id.return_type);
6388 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
6389 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
6390 }
6391 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
6392
6393 ir_set_cursor_at_end_and_append_block(irb, check_free_block);
6394 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6395 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
6396 incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
6397 incoming_values[0] = const_bool_false;
6398 incoming_blocks[1] = irb->exec->coro_normal_final;
6399 incoming_values[1] = const_bool_true;
6400 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
6401
6402 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
6403 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
6404 ImplicitAllocatorIdLocalVar);
6405 IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
6406 IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
6407 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6408 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
6409 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_mem_ptr_maybe);
6410 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
6411 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var, true, false);
6412 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
6413 IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false);
6414 size_t arg_count = 2;
6415 IrInstruction **args = allocate<IrInstruction *>(arg_count);
6416 args[0] = implicit_allocator_ptr; // self
6417 args[1] = mem_slice; // old_mem
6418 ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
6419
6420 IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
6421 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
6422
6423 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6424 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
6425 irb->exec->await_handle_var_ptr, false);
6426 IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
6427 ir_build_coro_resume(irb, scope, node, awaiter_handle);
6428 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
57526429 }
57536430
57546431 return true;
......@@ -6705,6 +7382,12 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
67057382 return result;
67067383 }
67077384
7385 if (expected_type == ira->codegen->builtin_types.entry_promise &&
7386 actual_type->id == TypeTableEntryIdPromise)
7387 {
7388 return result;
7389 }
7390
67087391 // fn
67097392 if (expected_type->id == TypeTableEntryIdFn &&
67107393 actual_type->id == TypeTableEntryIdFn)
......@@ -6736,6 +7419,16 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
67367419 return result;
67377420 }
67387421 }
7422 if (!expected_type->data.fn.is_generic && expected_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
7423 ConstCastOnly child = types_match_const_cast_only(ira, actual_type->data.fn.fn_type_id.async_allocator_type,
7424 expected_type->data.fn.fn_type_id.async_allocator_type, source_node);
7425 if (child.id != ConstCastResultIdOk) {
7426 result.id = ConstCastResultIdAsyncAllocatorType;
7427 result.data.async_allocator_type = allocate_nonzero<ConstCastOnly>(1);
7428 *result.data.async_allocator_type = child;
7429 return result;
7430 }
7431 }
67397432 if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
67407433 result.id = ConstCastResultIdFnArgCount;
67417434 return result;
......@@ -8817,16 +9510,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
88179510
88189511 // explicit cast from child type of maybe type to maybe type
88199512 if (wanted_type->id == TypeTableEntryIdMaybe) {
8820 if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) {
9513 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
9514 if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) {
88219515 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
88229516 } else if (actual_type->id == TypeTableEntryIdNumLitInt ||
88239517 actual_type->id == TypeTableEntryIdNumLitFloat)
88249518 {
8825 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) {
9519 if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
88269520 return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
88279521 } else {
88289522 return ira->codegen->invalid_instruction;
88299523 }
9524 } else if (wanted_child_type->id == TypeTableEntryIdPointer &&
9525 wanted_child_type->data.pointer.is_const &&
9526 (actual_type->id == TypeTableEntryIdPointer || is_container(actual_type)))
9527 {
9528 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value);
9529 if (type_is_invalid(cast1->value.type))
9530 return ira->codegen->invalid_instruction;
9531
9532 IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
9533 if (type_is_invalid(cast2->value.type))
9534 return ira->codegen->invalid_instruction;
9535
9536 return cast2;
88309537 }
88319538 }
88329539
......@@ -9210,15 +9917,35 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)
92109917 return ir_resolve_bool(ira, value, out);
92119918}
92129919
9213static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
9920static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
9921 if (type_is_invalid(value->value.type))
9922 return false;
9923
9924 ConstExprValue *atomic_order_val = get_builtin_value(ira->codegen, "AtomicOrder");
9925 assert(atomic_order_val->type->id == TypeTableEntryIdMetaType);
9926 TypeTableEntry *atomic_order_type = atomic_order_val->data.x_type;
9927
9928 IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_order_type);
9929 if (type_is_invalid(casted_value->value.type))
9930 return false;
9931
9932 ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
9933 if (!const_val)
9934 return false;
9935
9936 *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag);
9937 return true;
9938}
9939
9940static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, AtomicRmwOp *out) {
92149941 if (type_is_invalid(value->value.type))
92159942 return false;
92169943
9217 ConstExprValue *atomic_order_val = get_builtin_value(ira->codegen, "AtomicOrder");
9218 assert(atomic_order_val->type->id == TypeTableEntryIdMetaType);
9219 TypeTableEntry *atomic_order_type = atomic_order_val->data.x_type;
9944 ConstExprValue *atomic_rmw_op_val = get_builtin_value(ira->codegen, "AtomicRmwOp");
9945 assert(atomic_rmw_op_val->type->id == TypeTableEntryIdMetaType);
9946 TypeTableEntry *atomic_rmw_op_type = atomic_rmw_op_val->data.x_type;
92209947
9221 IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_order_type);
9948 IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_rmw_op_type);
92229949 if (type_is_invalid(casted_value->value.type))
92239950 return false;
92249951
......@@ -9226,7 +9953,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
92269953 if (!const_val)
92279954 return false;
92289955
9229 *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag);
9956 *out = (AtomicRmwOp)bigint_as_unsigned(&const_val->data.x_enum_tag);
92309957 return true;
92319958}
92329959
......@@ -9328,8 +10055,11 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
932810055 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
932910056 return ir_unreach_error(ira);
933010057 }
9331 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);
9332 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
10058 IrInstruction *result = ir_build_return(&ira->new_irb, return_instruction->base.scope,
10059 return_instruction->base.source_node, casted_value);
10060 result->value.type = ira->codegen->builtin_types.entry_unreachable;
10061 ir_link_new_instruction(result, &return_instruction->base);
10062 return ir_finish_anal(ira, result->value.type);
933310063}
933410064
933510065static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) {
......@@ -9554,6 +10284,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
955410284 case TypeTableEntryIdBlock:
955510285 case TypeTableEntryIdBoundFn:
955610286 case TypeTableEntryIdArgTuple:
10287 case TypeTableEntryIdPromise:
955710288 if (!is_equality_cmp) {
955810289 ir_add_error_node(ira, source_node,
955910290 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
......@@ -10383,6 +11114,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
1038311114 case TypeTableEntryIdVoid:
1038411115 case TypeTableEntryIdErrorSet:
1038511116 case TypeTableEntryIdFn:
11117 case TypeTableEntryIdPromise:
1038611118 return VarClassRequiredAny;
1038711119 case TypeTableEntryIdNumLitFloat:
1038811120 case TypeTableEntryIdNumLitInt:
......@@ -10559,6 +11291,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1055911291 buf_sprintf("exported function must specify calling convention"));
1056011292 add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
1056111293 } break;
11294 case CallingConventionAsync: {
11295 ErrorMsg *msg = ir_add_error(ira, target,
11296 buf_sprintf("exported function cannot be async"));
11297 add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
11298 } break;
1056211299 case CallingConventionC:
1056311300 case CallingConventionNaked:
1056411301 case CallingConventionCold:
......@@ -10648,6 +11385,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1064811385 case TypeTableEntryIdBoundFn:
1064911386 case TypeTableEntryIdArgTuple:
1065011387 case TypeTableEntryIdOpaque:
11388 case TypeTableEntryIdPromise:
1065111389 ir_add_error(ira, target,
1065211390 buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name)));
1065311391 break;
......@@ -10672,6 +11410,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
1067211410 case TypeTableEntryIdBoundFn:
1067311411 case TypeTableEntryIdArgTuple:
1067411412 case TypeTableEntryIdOpaque:
11413 case TypeTableEntryIdPromise:
1067511414 ir_add_error(ira, target,
1067611415 buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name)));
1067711416 break;
......@@ -10724,6 +11463,81 @@ static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
1072411463 return ira->codegen->builtin_types.entry_type;
1072511464}
1072611465
11466IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_instr, ImplicitAllocatorId id) {
11467 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
11468 if (parent_fn_entry == nullptr) {
11469 ir_add_error(ira, source_instr, buf_sprintf("no implicit allocator available"));
11470 return ira->codegen->invalid_instruction;
11471 }
11472
11473 FnTypeId *parent_fn_type = &parent_fn_entry->type_entry->data.fn.fn_type_id;
11474 if (parent_fn_type->cc != CallingConventionAsync) {
11475 ir_add_error(ira, source_instr, buf_sprintf("async function call from non-async caller requires allocator parameter"));
11476 return ira->codegen->invalid_instruction;
11477 }
11478
11479 assert(parent_fn_type->async_allocator_type != nullptr);
11480
11481 switch (id) {
11482 case ImplicitAllocatorIdArg:
11483 {
11484 IrInstruction *result = ir_build_get_implicit_allocator(&ira->new_irb, source_instr->scope,
11485 source_instr->source_node, ImplicitAllocatorIdArg);
11486 result->value.type = parent_fn_type->async_allocator_type;
11487 return result;
11488 }
11489 case ImplicitAllocatorIdLocalVar:
11490 {
11491 VariableTableEntry *coro_allocator_var = ira->old_irb.exec->coro_allocator_var;
11492 assert(coro_allocator_var != nullptr);
11493 IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var, true, false);
11494 IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst);
11495 assert(result->value.type != nullptr);
11496 return result;
11497 }
11498 }
11499 zig_unreachable();
11500}
11501
11502static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, FnTableEntry *fn_entry, TypeTableEntry *fn_type,
11503 IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst)
11504{
11505 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
11506 //Buf *free_field_name = buf_create_from_str("freeFn");
11507 assert(async_allocator_inst->value.type->id == TypeTableEntryIdPointer);
11508 TypeTableEntry *container_type = async_allocator_inst->value.type->data.pointer.child_type;
11509 IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, alloc_field_name, &call_instruction->base,
11510 async_allocator_inst, container_type);
11511 if (type_is_invalid(field_ptr_inst->value.type)) {
11512 return ira->codegen->invalid_instruction;
11513 }
11514 TypeTableEntry *ptr_to_alloc_fn_type = field_ptr_inst->value.type;
11515 assert(ptr_to_alloc_fn_type->id == TypeTableEntryIdPointer);
11516
11517 TypeTableEntry *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type;
11518 if (alloc_fn_type->id != TypeTableEntryIdFn) {
11519 ir_add_error(ira, &call_instruction->base,
11520 buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name)));
11521 return ira->codegen->invalid_instruction;
11522 }
11523
11524 TypeTableEntry *alloc_fn_return_type = alloc_fn_type->data.fn.fn_type_id.return_type;
11525 if (alloc_fn_return_type->id != TypeTableEntryIdErrorUnion) {
11526 ir_add_error(ira, fn_ref,
11527 buf_sprintf("expected allocation function to return error union, but it returns '%s'", buf_ptr(&alloc_fn_return_type->name)));
11528 return ira->codegen->invalid_instruction;
11529 }
11530 TypeTableEntry *alloc_fn_error_set_type = alloc_fn_return_type->data.error_union.err_set_type;
11531 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
11532 TypeTableEntry *promise_type = get_promise_type(ira->codegen, return_type);
11533 TypeTableEntry *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
11534
11535 IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
11536 fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst);
11537 result->value.type = async_return_type;
11538 return result;
11539}
11540
1072711541static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
1072811542 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
1072911543{
......@@ -10938,6 +11752,20 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1093811752 }
1093911753 return ira->codegen->builtin_types.entry_invalid;
1094011754 }
11755 if (fn_type_id->cc == CallingConventionAsync && !call_instruction->is_async) {
11756 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("must use async keyword to call async function"));
11757 if (fn_proto_node) {
11758 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
11759 }
11760 return ira->codegen->builtin_types.entry_invalid;
11761 }
11762 if (fn_type_id->cc != CallingConventionAsync && call_instruction->is_async) {
11763 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("cannot use async keyword to call non-async function"));
11764 if (fn_proto_node) {
11765 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
11766 }
11767 return ira->codegen->builtin_types.entry_invalid;
11768 }
1094111769
1094211770
1094311771 if (fn_type_id->is_var_args) {
......@@ -11064,6 +11892,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1106411892 buf_sprintf("calling a generic function requires compile-time known function value"));
1106511893 return ira->codegen->builtin_types.entry_invalid;
1106611894 }
11895 if (call_instruction->is_async && fn_type_id->is_var_args) {
11896 ir_add_error(ira, call_instruction->fn_ref,
11897 buf_sprintf("compiler bug: TODO: implement var args async functions. https://github.com/zig-lang/zig/issues/557"));
11898 return ira->codegen->builtin_types.entry_invalid;
11899 }
1106711900
1106811901 // Count the arguments of the function type id we are creating
1106911902 size_t new_fn_arg_count = first_arg_1_or_0;
......@@ -11212,6 +12045,36 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1121212045 return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
1121312046 }
1121412047 }
12048 IrInstruction *async_allocator_inst = nullptr;
12049 if (call_instruction->is_async) {
12050 AstNode *async_allocator_type_node = fn_proto_node->data.fn_proto.async_allocator_type;
12051 if (async_allocator_type_node != nullptr) {
12052 TypeTableEntry *async_allocator_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, async_allocator_type_node);
12053 if (type_is_invalid(async_allocator_type))
12054 return ira->codegen->builtin_types.entry_invalid;
12055 inst_fn_type_id.async_allocator_type = async_allocator_type;
12056 }
12057 IrInstruction *uncasted_async_allocator_inst;
12058 if (call_instruction->async_allocator == nullptr) {
12059 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
12060 ImplicitAllocatorIdLocalVar);
12061 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
12062 return ira->codegen->builtin_types.entry_invalid;
12063 } else {
12064 uncasted_async_allocator_inst = call_instruction->async_allocator->other;
12065 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
12066 return ira->codegen->builtin_types.entry_invalid;
12067 }
12068 if (inst_fn_type_id.async_allocator_type == nullptr) {
12069 IrInstruction *casted_inst = ir_implicit_byval_const_ref_cast(ira, uncasted_async_allocator_inst);
12070 if (type_is_invalid(casted_inst->value.type))
12071 return ira->codegen->builtin_types.entry_invalid;
12072 inst_fn_type_id.async_allocator_type = casted_inst->value.type;
12073 }
12074 async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
12075 if (type_is_invalid(async_allocator_inst->value.type))
12076 return ira->codegen->builtin_types.entry_invalid;
12077 }
1121512078
1121612079 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
1121712080 if (existing_entry) {
......@@ -11231,24 +12094,34 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1123112094 ira->codegen->fn_defs.append(impl_fn);
1123212095 }
1123312096
12097 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
12098 if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {
12099 parent_fn_entry->calls_errorable_function = true;
12100 }
12101
1123412102 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
12103 if (call_instruction->is_async) {
12104 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count,
12105 async_allocator_inst);
12106 ir_link_new_instruction(result, &call_instruction->base);
12107 ir_add_alloca(ira, result, result->value.type);
12108 return ir_finish_anal(ira, result->value.type);
12109 }
12110
12111 assert(async_allocator_inst == nullptr);
1123512112 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11236 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline);
12113 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
12114 call_instruction->is_async, nullptr);
1123712115
11238 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
1123912116 ir_add_alloca(ira, new_call_instruction, return_type);
1124012117
11241 if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) {
11242 parent_fn_entry->calls_errorable_function = true;
11243 }
11244
1124512118 return ir_finish_anal(ira, return_type);
1124612119 }
1124712120
1124812121 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
1124912122 assert(fn_type_id->return_type != nullptr);
1125012123 assert(parent_fn_entry != nullptr);
11251 if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
12124 if (fn_type_can_fail(fn_type_id)) {
1125212125 parent_fn_entry->calls_errorable_function = true;
1125312126 }
1125412127
......@@ -11303,8 +12176,33 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1130312176 if (type_is_invalid(return_type))
1130412177 return ira->codegen->builtin_types.entry_invalid;
1130512178
12179 if (call_instruction->is_async) {
12180 IrInstruction *uncasted_async_allocator_inst;
12181 if (call_instruction->async_allocator == nullptr) {
12182 uncasted_async_allocator_inst = ir_get_implicit_allocator(ira, &call_instruction->base,
12183 ImplicitAllocatorIdLocalVar);
12184 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
12185 return ira->codegen->builtin_types.entry_invalid;
12186 } else {
12187 uncasted_async_allocator_inst = call_instruction->async_allocator->other;
12188 if (type_is_invalid(uncasted_async_allocator_inst->value.type))
12189 return ira->codegen->builtin_types.entry_invalid;
12190
12191 }
12192 IrInstruction *async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, fn_type_id->async_allocator_type);
12193 if (type_is_invalid(async_allocator_inst->value.type))
12194 return ira->codegen->builtin_types.entry_invalid;
12195
12196 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count,
12197 async_allocator_inst);
12198 ir_link_new_instruction(result, &call_instruction->base);
12199 ir_add_alloca(ira, result, result->value.type);
12200 return ir_finish_anal(ira, result->value.type);
12201 }
12202
12203
1130612204 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11307 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline);
12205 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
1130812206
1130912207 ir_add_alloca(ira, new_call_instruction, return_type);
1131012208 return ir_finish_anal(ira, return_type);
......@@ -11430,6 +12328,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1143012328 case TypeTableEntryIdBlock:
1143112329 case TypeTableEntryIdBoundFn:
1143212330 case TypeTableEntryIdArgTuple:
12331 case TypeTableEntryIdPromise:
1143312332 {
1143412333 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
1143512334 out_val->data.x_type = get_maybe_type(ira->codegen, type_entry);
......@@ -11998,8 +12897,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1199812897 return return_type;
1199912898}
1200012899
12001static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
12002 TypeTableEntry *bare_struct_type, Buf *field_name, IrInstructionFieldPtr *field_ptr_instruction,
12900static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
12901 TypeTableEntry *bare_struct_type, Buf *field_name, IrInstruction *source_instr,
1200312902 IrInstruction *container_ptr, TypeTableEntry *container_type)
1200412903{
1200512904 if (!is_slice(bare_struct_type)) {
......@@ -12007,17 +12906,17 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
1200712906 auto entry = container_scope->decl_table.maybe_get(field_name);
1200812907 Tld *tld = entry ? entry->value : nullptr;
1200912908 if (tld && tld->id == TldIdFn) {
12010 resolve_top_level_decl(ira->codegen, tld, false, field_ptr_instruction->base.source_node);
12909 resolve_top_level_decl(ira->codegen, tld, false, source_instr->source_node);
1201112910 if (tld->resolution == TldResolutionInvalid)
12012 return ira->codegen->builtin_types.entry_invalid;
12911 return ira->codegen->invalid_instruction;
1201312912 TldFn *tld_fn = (TldFn *)tld;
1201412913 FnTableEntry *fn_entry = tld_fn->fn_entry;
1201512914 if (type_is_invalid(fn_entry->type_entry))
12016 return ira->codegen->builtin_types.entry_invalid;
12915 return ira->codegen->invalid_instruction;
1201712916
12018 IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, field_ptr_instruction->base.scope,
12019 field_ptr_instruction->base.source_node, fn_entry, container_ptr);
12020 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);
12917 IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
12918 source_instr->source_node, fn_entry, container_ptr);
12919 return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
1202112920 }
1202212921 }
1202312922 const char *prefix_name;
......@@ -12032,19 +12931,19 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
1203212931 } else {
1203312932 prefix_name = "";
1203412933 }
12035 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
12934 ir_add_error_node(ira, source_instr->source_node,
1203612935 buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name)));
12037 return ira->codegen->builtin_types.entry_invalid;
12936 return ira->codegen->invalid_instruction;
1203812937}
1203912938
1204012939
12041static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
12042 IrInstructionFieldPtr *field_ptr_instruction, IrInstruction *container_ptr, TypeTableEntry *container_type)
12940static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
12941 IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type)
1204312942{
1204412943 TypeTableEntry *bare_type = container_ref_type(container_type);
1204512944 ensure_complete_type(ira->codegen, bare_type);
1204612945 if (type_is_invalid(bare_type))
12047 return ira->codegen->builtin_types.entry_invalid;
12946 return ira->codegen->invalid_instruction;
1204812947
1204912948 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
1205012949 bool is_const = container_ptr->value.type->data.pointer.is_const;
......@@ -12061,46 +12960,51 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
1206112960 if (instr_is_comptime(container_ptr)) {
1206212961 ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
1206312962 if (!ptr_val)
12064 return ira->codegen->builtin_types.entry_invalid;
12963 return ira->codegen->invalid_instruction;
1206512964
1206612965 if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
1206712966 ConstExprValue *struct_val = const_ptr_pointee(ira->codegen, ptr_val);
1206812967 if (type_is_invalid(struct_val->type))
12069 return ira->codegen->builtin_types.entry_invalid;
12968 return ira->codegen->invalid_instruction;
1207012969 ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index];
1207112970 TypeTableEntry *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type,
1207212971 is_const, is_volatile, align_bytes,
1207312972 (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
1207412973 (uint32_t)unaligned_bit_count_for_result_type);
12075 ConstExprValue *const_val = ir_build_const_from(ira, &field_ptr_instruction->base);
12974 IrInstruction *result = ir_get_const(ira, source_instr);
12975 ConstExprValue *const_val = &result->value;
1207612976 const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
1207712977 const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
1207812978 const_val->data.x_ptr.data.base_struct.struct_val = struct_val;
1207912979 const_val->data.x_ptr.data.base_struct.field_index = field->src_index;
12080 return ptr_type;
12980 const_val->type = ptr_type;
12981 return result;
1208112982 }
1208212983 }
12083 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
12084 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
12984 IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
12985 container_ptr, field);
12986 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
1208512987 align_bytes,
1208612988 (uint32_t)(ptr_bit_offset + field->packed_bits_offset),
1208712989 (uint32_t)unaligned_bit_count_for_result_type);
12990 return result;
1208812991 } else {
1208912992 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
12090 field_ptr_instruction, container_ptr, container_type);
12993 source_instr, container_ptr, container_type);
1209112994 }
1209212995 } else if (bare_type->id == TypeTableEntryIdEnum) {
1209312996 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
12094 field_ptr_instruction, container_ptr, container_type);
12997 source_instr, container_ptr, container_type);
1209512998 } else if (bare_type->id == TypeTableEntryIdUnion) {
1209612999 TypeUnionField *field = find_union_type_field(bare_type, field_name);
1209713000 if (field) {
12098 ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
12099 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
13001 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
13002 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
1210013003 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
13004 return result;
1210113005 } else {
1210213006 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
12103 field_ptr_instruction, container_ptr, container_type);
13007 source_instr, container_ptr, container_type);
1210413008 }
1210513009 } else {
1210613010 zig_unreachable();
......@@ -12210,9 +13114,13 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1221013114 if (container_type->id == TypeTableEntryIdPointer) {
1221113115 TypeTableEntry *bare_type = container_ref_type(container_type);
1221213116 IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr);
12213 return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_child, bare_type);
13117 IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type);
13118 ir_link_new_instruction(result, &field_ptr_instruction->base);
13119 return result->value.type;
1221413120 } else {
12215 return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_ptr, container_type);
13121 IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type);
13122 ir_link_new_instruction(result, &field_ptr_instruction->base);
13123 return result->value.type;
1221613124 }
1221713125 } else if (container_type->id == TypeTableEntryIdArray) {
1221813126 if (buf_eql_str(field_name, "len")) {
......@@ -12659,6 +13567,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
1265913567 case TypeTableEntryIdFn:
1266013568 case TypeTableEntryIdArgTuple:
1266113569 case TypeTableEntryIdOpaque:
13570 case TypeTableEntryIdPromise:
1266213571 {
1266313572 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base);
1266413573 out_val->data.x_type = type_entry;
......@@ -12926,6 +13835,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1292613835 case TypeTableEntryIdFn:
1292713836 case TypeTableEntryIdNamespace:
1292813837 case TypeTableEntryIdBoundFn:
13838 case TypeTableEntryIdPromise:
1292913839 {
1293013840 type_ensure_zero_bits_known(ira->codegen, child_type);
1293113841 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
......@@ -13034,6 +13944,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
1303413944 case TypeTableEntryIdFn:
1303513945 case TypeTableEntryIdNamespace:
1303613946 case TypeTableEntryIdBoundFn:
13947 case TypeTableEntryIdPromise:
1303713948 {
1303813949 TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
1303913950 ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base);
......@@ -13085,6 +13996,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
1308513996 case TypeTableEntryIdEnum:
1308613997 case TypeTableEntryIdUnion:
1308713998 case TypeTableEntryIdFn:
13999 case TypeTableEntryIdPromise:
1308814000 {
1308914001 uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
1309014002 ConstExprValue *out_val = ir_build_const_from(ira, &size_of_instruction->base);
......@@ -13414,6 +14326,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1341414326 case TypeTableEntryIdNumLitFloat:
1341514327 case TypeTableEntryIdNumLitInt:
1341614328 case TypeTableEntryIdPointer:
14329 case TypeTableEntryIdPromise:
1341714330 case TypeTableEntryIdFn:
1341814331 case TypeTableEntryIdNamespace:
1341914332 case TypeTableEntryIdErrorSet:
......@@ -14002,6 +14915,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
1400214915 case TypeTableEntryIdMetaType:
1400314916 case TypeTableEntryIdUnreachable:
1400414917 case TypeTableEntryIdPointer:
14918 case TypeTableEntryIdPromise:
1400514919 case TypeTableEntryIdArray:
1400614920 case TypeTableEntryIdStruct:
1400714921 case TypeTableEntryIdNumLitFloat:
......@@ -15262,6 +16176,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
1526216176 case TypeTableEntryIdInt:
1526316177 case TypeTableEntryIdFloat:
1526416178 case TypeTableEntryIdPointer:
16179 case TypeTableEntryIdPromise:
1526516180 case TypeTableEntryIdArray:
1526616181 case TypeTableEntryIdStruct:
1526716182 case TypeTableEntryIdMaybe:
......@@ -15890,12 +16805,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
1589016805 if (type_is_invalid(src_type))
1589116806 return ira->codegen->builtin_types.entry_invalid;
1589216807
15893 if (!type_is_codegen_pointer(src_type)) {
16808 if (get_codegen_ptr_type(src_type) == nullptr) {
1589416809 ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
1589516810 return ira->codegen->builtin_types.entry_invalid;
1589616811 }
1589716812
15898 if (!type_is_codegen_pointer(dest_type)) {
16813 if (get_codegen_ptr_type(dest_type) == nullptr) {
1589916814 ir_add_error(ira, dest_type_value,
1590016815 buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
1590116816 return ira->codegen->builtin_types.entry_invalid;
......@@ -15957,6 +16872,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1595716872 case TypeTableEntryIdNumLitInt:
1595816873 case TypeTableEntryIdUndefLit:
1595916874 case TypeTableEntryIdNullLit:
16875 case TypeTableEntryIdPromise:
1596016876 zig_unreachable();
1596116877 case TypeTableEntryIdVoid:
1596216878 return;
......@@ -16024,6 +16940,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
1602416940 case TypeTableEntryIdNumLitInt:
1602516941 case TypeTableEntryIdUndefLit:
1602616942 case TypeTableEntryIdNullLit:
16943 case TypeTableEntryIdPromise:
1602716944 zig_unreachable();
1602816945 case TypeTableEntryIdVoid:
1602916946 return;
......@@ -16080,9 +16997,9 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
1608016997 ensure_complete_type(ira->codegen, dest_type);
1608116998 ensure_complete_type(ira->codegen, src_type);
1608216999
16083 if (type_is_codegen_pointer(src_type)) {
17000 if (get_codegen_ptr_type(src_type) != nullptr) {
1608417001 ir_add_error(ira, value,
16085 buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
17002 buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
1608617003 return ira->codegen->builtin_types.entry_invalid;
1608717004 }
1608817005
......@@ -16107,9 +17024,9 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
1610717024 break;
1610817025 }
1610917026
16110 if (type_is_codegen_pointer(dest_type)) {
17027 if (get_codegen_ptr_type(dest_type) != nullptr) {
1611117028 ir_add_error(ira, dest_type_value,
16112 buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
17029 buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
1611317030 return ira->codegen->builtin_types.entry_invalid;
1611417031 }
1611517032
......@@ -16170,7 +17087,7 @@ static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstr
1617017087 if (type_is_invalid(dest_type))
1617117088 return ira->codegen->builtin_types.entry_invalid;
1617217089
16173 if (!type_is_codegen_pointer(dest_type)) {
17090 if (get_codegen_ptr_type(dest_type) == nullptr) {
1617417091 ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
1617517092 return ira->codegen->builtin_types.entry_invalid;
1617617093 }
......@@ -16276,12 +17193,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
1627617193
1627717194 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1627817195
16279 if (!(target->value.type->id == TypeTableEntryIdPointer ||
16280 target->value.type->id == TypeTableEntryIdFn ||
16281 (target->value.type->id == TypeTableEntryIdMaybe &&
16282 (target->value.type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
16283 target->value.type->data.maybe.child_type->id == TypeTableEntryIdFn))))
16284 {
17196 if (get_codegen_ptr_type(target->value.type) == nullptr) {
1628517197 ir_add_error(ira, target,
1628617198 buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name)));
1628717199 return ira->codegen->builtin_types.entry_invalid;
......@@ -16465,6 +17377,292 @@ static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruc
1646517377 }
1646617378}
1646717379
17380static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
17381 IrInstruction *target_inst = instruction->target->other;
17382 if (type_is_invalid(target_inst->value.type))
17383 return ira->codegen->builtin_types.entry_invalid;
17384 IrInstruction *casted_target = ir_implicit_cast(ira, target_inst, ira->codegen->builtin_types.entry_promise);
17385 if (type_is_invalid(casted_target->value.type))
17386 return ira->codegen->builtin_types.entry_invalid;
17387
17388 IrInstruction *result = ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_target);
17389 result->value.type = ira->codegen->builtin_types.entry_void;
17390 result->value.special = ConstValSpecialStatic;
17391 ir_link_new_instruction(result, &instruction->base);
17392 return result->value.type;
17393}
17394
17395static TypeTableEntry *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) {
17396 IrInstruction *promise_ptr = instruction->promise_ptr->other;
17397 if (type_is_invalid(promise_ptr->value.type))
17398 return ira->codegen->builtin_types.entry_invalid;
17399
17400 IrInstruction *result = ir_build_coro_id(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
17401 promise_ptr);
17402 ir_link_new_instruction(result, &instruction->base);
17403 result->value.type = ira->codegen->builtin_types.entry_usize;
17404 return result->value.type;
17405}
17406
17407static TypeTableEntry *ir_analyze_instruction_coro_alloc(IrAnalyze *ira, IrInstructionCoroAlloc *instruction) {
17408 IrInstruction *coro_id = instruction->coro_id->other;
17409 if (type_is_invalid(coro_id->value.type))
17410 return ira->codegen->builtin_types.entry_invalid;
17411
17412 IrInstruction *result = ir_build_coro_alloc(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
17413 coro_id);
17414 ir_link_new_instruction(result, &instruction->base);
17415 result->value.type = ira->codegen->builtin_types.entry_bool;
17416 return result->value.type;
17417}
17418
17419static TypeTableEntry *ir_analyze_instruction_coro_size(IrAnalyze *ira, IrInstructionCoroSize *instruction) {
17420 IrInstruction *result = ir_build_coro_size(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
17421 ir_link_new_instruction(result, &instruction->base);
17422 result->value.type = ira->codegen->builtin_types.entry_usize;
17423 return result->value.type;
17424}
17425
17426static TypeTableEntry *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstructionCoroBegin *instruction) {
17427 IrInstruction *coro_id = instruction->coro_id->other;
17428 if (type_is_invalid(coro_id->value.type))
17429 return ira->codegen->builtin_types.entry_invalid;
17430
17431 IrInstruction *coro_mem_ptr = instruction->coro_mem_ptr->other;
17432 if (type_is_invalid(coro_mem_ptr->value.type))
17433 return ira->codegen->builtin_types.entry_invalid;
17434
17435 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
17436 assert(fn_entry != nullptr);
17437 IrInstruction *result = ir_build_coro_begin(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
17438 coro_id, coro_mem_ptr);
17439 ir_link_new_instruction(result, &instruction->base);
17440 result->value.type = get_promise_type(ira->codegen, fn_entry->type_entry->data.fn.fn_type_id.return_type);
17441 return result->value.type;
17442}
17443
17444static TypeTableEntry *ir_analyze_instruction_get_implicit_allocator(IrAnalyze *ira, IrInstructionGetImplicitAllocator *instruction) {
17445 IrInstruction *result = ir_get_implicit_allocator(ira, &instruction->base, instruction->id);
17446 ir_link_new_instruction(result, &instruction->base);
17447 return result->value.type;
17448}
17449
17450static TypeTableEntry *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, IrInstructionCoroAllocFail *instruction) {
17451 IrInstruction *err_val = instruction->err_val->other;
17452 if (type_is_invalid(err_val->value.type))
17453 return ir_unreach_error(ira);
17454
17455 IrInstruction *result = ir_build_coro_alloc_fail(&ira->new_irb, instruction->base.scope, instruction->base.source_node, err_val);
17456 ir_link_new_instruction(result, &instruction->base);
17457 result->value.type = ira->codegen->builtin_types.entry_unreachable;
17458 return ir_finish_anal(ira, result->value.type);
17459}
17460
17461static TypeTableEntry *ir_analyze_instruction_coro_suspend(IrAnalyze *ira, IrInstructionCoroSuspend *instruction) {
17462 IrInstruction *save_point = nullptr;
17463 if (instruction->save_point != nullptr) {
17464 save_point = instruction->save_point->other;
17465 if (type_is_invalid(save_point->value.type))
17466 return ira->codegen->builtin_types.entry_invalid;
17467 }
17468
17469 IrInstruction *is_final = instruction->is_final->other;
17470 if (type_is_invalid(is_final->value.type))
17471 return ira->codegen->builtin_types.entry_invalid;
17472
17473 IrInstruction *result = ir_build_coro_suspend(&ira->new_irb, instruction->base.scope,
17474 instruction->base.source_node, save_point, is_final);
17475 ir_link_new_instruction(result, &instruction->base);
17476 result->value.type = ira->codegen->builtin_types.entry_u8;
17477 return result->value.type;
17478}
17479
17480static TypeTableEntry *ir_analyze_instruction_coro_end(IrAnalyze *ira, IrInstructionCoroEnd *instruction) {
17481 IrInstruction *result = ir_build_coro_end(&ira->new_irb, instruction->base.scope,
17482 instruction->base.source_node);
17483 ir_link_new_instruction(result, &instruction->base);
17484 result->value.type = ira->codegen->builtin_types.entry_void;
17485 return result->value.type;
17486}
17487
17488static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstructionCoroFree *instruction) {
17489 IrInstruction *coro_id = instruction->coro_id->other;
17490 if (type_is_invalid(coro_id->value.type))
17491 return ira->codegen->builtin_types.entry_invalid;
17492
17493 IrInstruction *coro_handle = instruction->coro_handle->other;
17494 if (type_is_invalid(coro_handle->value.type))
17495 return ira->codegen->builtin_types.entry_invalid;
17496
17497 IrInstruction *result = ir_build_coro_free(&ira->new_irb, instruction->base.scope,
17498 instruction->base.source_node, coro_id, coro_handle);
17499 ir_link_new_instruction(result, &instruction->base);
17500 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
17501 result->value.type = get_maybe_type(ira->codegen, ptr_type);
17502 return result->value.type;
17503}
17504
17505static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {
17506 IrInstruction *awaiter_handle = instruction->awaiter_handle->other;
17507 if (type_is_invalid(awaiter_handle->value.type))
17508 return ira->codegen->builtin_types.entry_invalid;
17509
17510 IrInstruction *casted_target = ir_implicit_cast(ira, awaiter_handle, ira->codegen->builtin_types.entry_promise);
17511 if (type_is_invalid(casted_target->value.type))
17512 return ira->codegen->builtin_types.entry_invalid;
17513
17514 IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope,
17515 instruction->base.source_node, casted_target);
17516 ir_link_new_instruction(result, &instruction->base);
17517 result->value.type = ira->codegen->builtin_types.entry_void;
17518 return result->value.type;
17519}
17520
17521static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstructionCoroSave *instruction) {
17522 IrInstruction *coro_handle = instruction->coro_handle->other;
17523 if (type_is_invalid(coro_handle->value.type))
17524 return ira->codegen->builtin_types.entry_invalid;
17525
17526 IrInstruction *result = ir_build_coro_save(&ira->new_irb, instruction->base.scope,
17527 instruction->base.source_node, coro_handle);
17528 ir_link_new_instruction(result, &instruction->base);
17529 result->value.type = ira->codegen->builtin_types.entry_usize;
17530 return result->value.type;
17531}
17532
17533static TypeTableEntry *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInstructionCoroPromise *instruction) {
17534 IrInstruction *coro_handle = instruction->coro_handle->other;
17535 if (type_is_invalid(coro_handle->value.type))
17536 return ira->codegen->builtin_types.entry_invalid;
17537
17538 if (coro_handle->value.type->id != TypeTableEntryIdPromise ||
17539 coro_handle->value.type->data.promise.result_type == nullptr)
17540 {
17541 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
17542 buf_ptr(&coro_handle->value.type->name)));
17543 return ira->codegen->builtin_types.entry_invalid;
17544 }
17545
17546 TypeTableEntry *coro_frame_type = get_promise_frame_type(ira->codegen,
17547 coro_handle->value.type->data.promise.result_type);
17548
17549 IrInstruction *result = ir_build_coro_promise(&ira->new_irb, instruction->base.scope,
17550 instruction->base.source_node, coro_handle);
17551 ir_link_new_instruction(result, &instruction->base);
17552 result->value.type = get_pointer_to_type(ira->codegen, coro_frame_type, false);
17553 return result->value.type;
17554}
17555
17556static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {
17557 IrInstruction *alloc_fn = instruction->alloc_fn->other;
17558 if (type_is_invalid(alloc_fn->value.type))
17559 return ira->codegen->builtin_types.entry_invalid;
17560
17561 IrInstruction *coro_size = instruction->coro_size->other;
17562 if (type_is_invalid(coro_size->value.type))
17563 return ira->codegen->builtin_types.entry_invalid;
17564
17565 IrInstruction *result = ir_build_coro_alloc_helper(&ira->new_irb, instruction->base.scope,
17566 instruction->base.source_node, alloc_fn, coro_size);
17567 ir_link_new_instruction(result, &instruction->base);
17568 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
17569 result->value.type = get_maybe_type(ira->codegen, u8_ptr_type);
17570 return result->value.type;
17571}
17572
17573static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstructionAtomicRmw *instruction) {
17574 TypeTableEntry *operand_type = ir_resolve_type(ira, instruction->operand_type->other);
17575 if (type_is_invalid(operand_type)) {
17576 return ira->codegen->builtin_types.entry_invalid;
17577 }
17578 if (operand_type->id == TypeTableEntryIdInt) {
17579 if (operand_type->data.integral.bit_count < 8) {
17580 ir_add_error(ira, &instruction->base,
17581 buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type",
17582 operand_type->data.integral.bit_count));
17583 return ira->codegen->builtin_types.entry_invalid;
17584 }
17585 if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
17586 ir_add_error(ira, &instruction->base,
17587 buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
17588 operand_type->data.integral.bit_count));
17589 return ira->codegen->builtin_types.entry_invalid;
17590 }
17591 if (!is_power_of_2(operand_type->data.integral.bit_count)) {
17592 ir_add_error(ira, &instruction->base,
17593 buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count));
17594 return ira->codegen->builtin_types.entry_invalid;
17595 }
17596 } else if (get_codegen_ptr_type(operand_type) == nullptr) {
17597 ir_add_error(ira, &instruction->base,
17598 buf_sprintf("expected integer or pointer type, found '%s'", buf_ptr(&operand_type->name)));
17599 return ira->codegen->builtin_types.entry_invalid;
17600 }
17601
17602 IrInstruction *ptr_inst = instruction->ptr->other;
17603 if (type_is_invalid(ptr_inst->value.type))
17604 return ira->codegen->builtin_types.entry_invalid;
17605
17606 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
17607 IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr_inst, ptr_type);
17608 if (type_is_invalid(casted_ptr->value.type))
17609 return ira->codegen->builtin_types.entry_invalid;
17610
17611 AtomicRmwOp op;
17612 if (instruction->op == nullptr) {
17613 op = instruction->resolved_op;
17614 } else {
17615 if (!ir_resolve_atomic_rmw_op(ira, instruction->op->other, &op)) {
17616 return ira->codegen->builtin_types.entry_invalid;
17617 }
17618 }
17619
17620 IrInstruction *operand = instruction->operand->other;
17621 if (type_is_invalid(operand->value.type))
17622 return ira->codegen->builtin_types.entry_invalid;
17623
17624 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, operand_type);
17625 if (type_is_invalid(casted_ptr->value.type))
17626 return ira->codegen->builtin_types.entry_invalid;
17627
17628 AtomicOrder ordering;
17629 if (instruction->ordering == nullptr) {
17630 ordering = instruction->resolved_ordering;
17631 } else {
17632 if (!ir_resolve_atomic_order(ira, instruction->ordering->other, &ordering))
17633 return ira->codegen->builtin_types.entry_invalid;
17634 }
17635
17636 if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
17637 {
17638 zig_panic("TODO compile-time execution of atomicRmw");
17639 }
17640
17641 IrInstruction *result = ir_build_atomic_rmw(&ira->new_irb, instruction->base.scope,
17642 instruction->base.source_node, nullptr, casted_ptr, nullptr, casted_operand, nullptr,
17643 op, ordering);
17644 ir_link_new_instruction(result, &instruction->base);
17645 result->value.type = operand_type;
17646 return result->value.type;
17647}
17648
17649static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) {
17650 TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other);
17651 if (type_is_invalid(promise_type))
17652 return ira->codegen->builtin_types.entry_invalid;
17653
17654 if (promise_type->id != TypeTableEntryIdPromise || promise_type->data.promise.result_type == nullptr) {
17655 ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'",
17656 buf_ptr(&promise_type->name)));
17657 return ira->codegen->builtin_types.entry_invalid;
17658 }
17659
17660 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17661 out_val->data.x_type = promise_type->data.promise.result_type;
17662 return ira->codegen->builtin_types.entry_type;
17663}
17664
17665
1646817666static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1646917667 switch (instruction->id) {
1647017668 case IrInstructionIdInvalid:
......@@ -16667,6 +17865,38 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1666717865 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
1666817866 case IrInstructionIdErrorUnion:
1666917867 return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
17868 case IrInstructionIdCancel:
17869 return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction);
17870 case IrInstructionIdCoroId:
17871 return ir_analyze_instruction_coro_id(ira, (IrInstructionCoroId *)instruction);
17872 case IrInstructionIdCoroAlloc:
17873 return ir_analyze_instruction_coro_alloc(ira, (IrInstructionCoroAlloc *)instruction);
17874 case IrInstructionIdCoroSize:
17875 return ir_analyze_instruction_coro_size(ira, (IrInstructionCoroSize *)instruction);
17876 case IrInstructionIdCoroBegin:
17877 return ir_analyze_instruction_coro_begin(ira, (IrInstructionCoroBegin *)instruction);
17878 case IrInstructionIdGetImplicitAllocator:
17879 return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction);
17880 case IrInstructionIdCoroAllocFail:
17881 return ir_analyze_instruction_coro_alloc_fail(ira, (IrInstructionCoroAllocFail *)instruction);
17882 case IrInstructionIdCoroSuspend:
17883 return ir_analyze_instruction_coro_suspend(ira, (IrInstructionCoroSuspend *)instruction);
17884 case IrInstructionIdCoroEnd:
17885 return ir_analyze_instruction_coro_end(ira, (IrInstructionCoroEnd *)instruction);
17886 case IrInstructionIdCoroFree:
17887 return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction);
17888 case IrInstructionIdCoroResume:
17889 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
17890 case IrInstructionIdCoroSave:
17891 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
17892 case IrInstructionIdCoroPromise:
17893 return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction);
17894 case IrInstructionIdCoroAllocHelper:
17895 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
17896 case IrInstructionIdAtomicRmw:
17897 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
17898 case IrInstructionIdPromiseResultType:
17899 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
1667017900 }
1667117901 zig_unreachable();
1667217902}
......@@ -16696,7 +17926,10 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
1669617926 IrAnalyze *ira = allocate<IrAnalyze>(1);
1669717927 old_exec->analysis = ira;
1669817928 ira->codegen = codegen;
16699 ira->explicit_return_type = expected_type;
17929
17930 FnTableEntry *fn_entry = exec_fn_entry(old_exec);
17931 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
17932 ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type;
1670017933
1670117934 ira->old_irb.codegen = codegen;
1670217935 ira->old_irb.exec = old_exec;
......@@ -16780,7 +18013,16 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1678018013 case IrInstructionIdPtrTypeOf:
1678118014 case IrInstructionIdSetAlignStack:
1678218015 case IrInstructionIdExport:
18016 case IrInstructionIdCancel:
18017 case IrInstructionIdCoroId:
18018 case IrInstructionIdCoroBegin:
18019 case IrInstructionIdCoroAllocFail:
18020 case IrInstructionIdCoroEnd:
18021 case IrInstructionIdCoroResume:
18022 case IrInstructionIdCoroSave:
18023 case IrInstructionIdCoroAllocHelper:
1678318024 return true;
18025
1678418026 case IrInstructionIdPhi:
1678518027 case IrInstructionIdUnOp:
1678618028 case IrInstructionIdBinOp:
......@@ -16853,7 +18095,16 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1685318095 case IrInstructionIdTagType:
1685418096 case IrInstructionIdErrorReturnTrace:
1685518097 case IrInstructionIdErrorUnion:
18098 case IrInstructionIdGetImplicitAllocator:
18099 case IrInstructionIdCoroAlloc:
18100 case IrInstructionIdCoroSize:
18101 case IrInstructionIdCoroSuspend:
18102 case IrInstructionIdCoroFree:
18103 case IrInstructionIdAtomicRmw:
18104 case IrInstructionIdCoroPromise:
18105 case IrInstructionIdPromiseResultType:
1685618106 return false;
18107
1685718108 case IrInstructionIdAsm:
1685818109 {
1685918110 IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;
src/ir_print.cpp+193
......@@ -198,6 +198,15 @@ static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
198198}
199199
200200static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
201 if (call_instruction->is_async) {
202 fprintf(irp->f, "async");
203 if (call_instruction->async_allocator != nullptr) {
204 fprintf(irp->f, "(");
205 ir_print_other_instruction(irp, call_instruction->async_allocator);
206 fprintf(irp->f, ")");
207 }
208 fprintf(irp->f, " ");
209 }
201210 if (call_instruction->fn_entry) {
202211 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
203212 } else {
......@@ -830,6 +839,12 @@ static void ir_print_ptr_to_int(IrPrint *irp, IrInstructionPtrToInt *instruction
830839
831840static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction) {
832841 fprintf(irp->f, "@intToPtr(");
842 if (instruction->dest_type == nullptr) {
843 fprintf(irp->f, "(null)");
844 } else {
845 ir_print_other_instruction(irp, instruction->dest_type);
846 }
847 fprintf(irp->f, ",");
833848 ir_print_other_instruction(irp, instruction->target);
834849 fprintf(irp->f, ")");
835850}
......@@ -1010,6 +1025,136 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
10101025 ir_print_other_instruction(irp, instruction->payload);
10111026}
10121027
1028static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
1029 fprintf(irp->f, "cancel ");
1030 ir_print_other_instruction(irp, instruction->target);
1031}
1032
1033static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplicitAllocator *instruction) {
1034 fprintf(irp->f, "@getImplicitAllocator(");
1035 switch (instruction->id) {
1036 case ImplicitAllocatorIdArg:
1037 fprintf(irp->f, "Arg");
1038 break;
1039 case ImplicitAllocatorIdLocalVar:
1040 fprintf(irp->f, "LocalVar");
1041 break;
1042 }
1043 fprintf(irp->f, ")");
1044}
1045
1046static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1047 fprintf(irp->f, "@coroId(");
1048 ir_print_other_instruction(irp, instruction->promise_ptr);
1049 fprintf(irp->f, ")");
1050}
1051
1052static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
1053 fprintf(irp->f, "@coroAlloc(");
1054 ir_print_other_instruction(irp, instruction->coro_id);
1055 fprintf(irp->f, ")");
1056}
1057
1058static void ir_print_coro_size(IrPrint *irp, IrInstructionCoroSize *instruction) {
1059 fprintf(irp->f, "@coroSize()");
1060}
1061
1062static void ir_print_coro_begin(IrPrint *irp, IrInstructionCoroBegin *instruction) {
1063 fprintf(irp->f, "@coroBegin(");
1064 ir_print_other_instruction(irp, instruction->coro_id);
1065 fprintf(irp->f, ",");
1066 ir_print_other_instruction(irp, instruction->coro_mem_ptr);
1067 fprintf(irp->f, ")");
1068}
1069
1070static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *instruction) {
1071 fprintf(irp->f, "@coroAllocFail(");
1072 ir_print_other_instruction(irp, instruction->err_val);
1073 fprintf(irp->f, ")");
1074}
1075
1076static void ir_print_coro_suspend(IrPrint *irp, IrInstructionCoroSuspend *instruction) {
1077 fprintf(irp->f, "@coroSuspend(");
1078 if (instruction->save_point != nullptr) {
1079 ir_print_other_instruction(irp, instruction->save_point);
1080 } else {
1081 fprintf(irp->f, "null");
1082 }
1083 fprintf(irp->f, ",");
1084 ir_print_other_instruction(irp, instruction->is_final);
1085 fprintf(irp->f, ")");
1086}
1087
1088static void ir_print_coro_end(IrPrint *irp, IrInstructionCoroEnd *instruction) {
1089 fprintf(irp->f, "@coroEnd()");
1090}
1091
1092static void ir_print_coro_free(IrPrint *irp, IrInstructionCoroFree *instruction) {
1093 fprintf(irp->f, "@coroFree(");
1094 ir_print_other_instruction(irp, instruction->coro_id);
1095 fprintf(irp->f, ",");
1096 ir_print_other_instruction(irp, instruction->coro_handle);
1097 fprintf(irp->f, ")");
1098}
1099
1100static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) {
1101 fprintf(irp->f, "@coroResume(");
1102 ir_print_other_instruction(irp, instruction->awaiter_handle);
1103 fprintf(irp->f, ")");
1104}
1105
1106static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction) {
1107 fprintf(irp->f, "@coroSave(");
1108 ir_print_other_instruction(irp, instruction->coro_handle);
1109 fprintf(irp->f, ")");
1110}
1111
1112static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1113 fprintf(irp->f, "@coroPromise(");
1114 ir_print_other_instruction(irp, instruction->coro_handle);
1115 fprintf(irp->f, ")");
1116}
1117
1118static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1119 fprintf(irp->f, "@PromiseResultType(");
1120 ir_print_other_instruction(irp, instruction->promise_type);
1121 fprintf(irp->f, ")");
1122}
1123
1124static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
1125 fprintf(irp->f, "@coroAllocHelper(");
1126 ir_print_other_instruction(irp, instruction->alloc_fn);
1127 fprintf(irp->f, ",");
1128 ir_print_other_instruction(irp, instruction->coro_size);
1129 fprintf(irp->f, ")");
1130}
1131
1132static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
1133 fprintf(irp->f, "@atomicRmw(");
1134 if (instruction->operand_type != nullptr) {
1135 ir_print_other_instruction(irp, instruction->operand_type);
1136 } else {
1137 fprintf(irp->f, "[TODO print]");
1138 }
1139 fprintf(irp->f, ",");
1140 ir_print_other_instruction(irp, instruction->ptr);
1141 fprintf(irp->f, ",");
1142 if (instruction->op != nullptr) {
1143 ir_print_other_instruction(irp, instruction->op);
1144 } else {
1145 fprintf(irp->f, "[TODO print]");
1146 }
1147 fprintf(irp->f, ",");
1148 ir_print_other_instruction(irp, instruction->operand);
1149 fprintf(irp->f, ",");
1150 if (instruction->ordering != nullptr) {
1151 ir_print_other_instruction(irp, instruction->ordering);
1152 } else {
1153 fprintf(irp->f, "[TODO print]");
1154 }
1155 fprintf(irp->f, ")");
1156}
1157
10131158static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10141159 ir_print_prefix(irp, instruction);
10151160 switch (instruction->id) {
......@@ -1330,6 +1475,54 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13301475 case IrInstructionIdErrorUnion:
13311476 ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
13321477 break;
1478 case IrInstructionIdCancel:
1479 ir_print_cancel(irp, (IrInstructionCancel *)instruction);
1480 break;
1481 case IrInstructionIdGetImplicitAllocator:
1482 ir_print_get_implicit_allocator(irp, (IrInstructionGetImplicitAllocator *)instruction);
1483 break;
1484 case IrInstructionIdCoroId:
1485 ir_print_coro_id(irp, (IrInstructionCoroId *)instruction);
1486 break;
1487 case IrInstructionIdCoroAlloc:
1488 ir_print_coro_alloc(irp, (IrInstructionCoroAlloc *)instruction);
1489 break;
1490 case IrInstructionIdCoroSize:
1491 ir_print_coro_size(irp, (IrInstructionCoroSize *)instruction);
1492 break;
1493 case IrInstructionIdCoroBegin:
1494 ir_print_coro_begin(irp, (IrInstructionCoroBegin *)instruction);
1495 break;
1496 case IrInstructionIdCoroAllocFail:
1497 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);
1498 break;
1499 case IrInstructionIdCoroSuspend:
1500 ir_print_coro_suspend(irp, (IrInstructionCoroSuspend *)instruction);
1501 break;
1502 case IrInstructionIdCoroEnd:
1503 ir_print_coro_end(irp, (IrInstructionCoroEnd *)instruction);
1504 break;
1505 case IrInstructionIdCoroFree:
1506 ir_print_coro_free(irp, (IrInstructionCoroFree *)instruction);
1507 break;
1508 case IrInstructionIdCoroResume:
1509 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
1510 break;
1511 case IrInstructionIdCoroSave:
1512 ir_print_coro_save(irp, (IrInstructionCoroSave *)instruction);
1513 break;
1514 case IrInstructionIdCoroAllocHelper:
1515 ir_print_coro_alloc_helper(irp, (IrInstructionCoroAllocHelper *)instruction);
1516 break;
1517 case IrInstructionIdAtomicRmw:
1518 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
1519 break;
1520 case IrInstructionIdCoroPromise:
1521 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
1522 break;
1523 case IrInstructionIdPromiseResultType:
1524 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
1525 break;
13331526 }
13341527 fprintf(irp->f, "\n");
13351528}
src/parser.cpp+170-9
......@@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo
221221static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);
222222static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);
223223static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index);
224static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index);
224225static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index);
225226
226227static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
......@@ -650,6 +651,41 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, size_t *token_index, bool m
650651 return node;
651652}
652653
654/*
655SuspendExpression(body) = "suspend" "|" Symbol "|" body
656*/
657static AstNode *ast_parse_suspend_block(ParseContext *pc, size_t *token_index, bool mandatory) {
658 size_t orig_token_index = *token_index;
659
660 Token *suspend_token = &pc->tokens->at(*token_index);
661 if (suspend_token->id == TokenIdKeywordSuspend) {
662 *token_index += 1;
663 } else if (mandatory) {
664 ast_expect_token(pc, suspend_token, TokenIdKeywordSuspend);
665 zig_unreachable();
666 } else {
667 return nullptr;
668 }
669
670 Token *bar_token = &pc->tokens->at(*token_index);
671 if (bar_token->id == TokenIdBinOr) {
672 *token_index += 1;
673 } else if (mandatory) {
674 ast_expect_token(pc, suspend_token, TokenIdBinOr);
675 zig_unreachable();
676 } else {
677 *token_index = orig_token_index;
678 return nullptr;
679 }
680
681 AstNode *node = ast_create_node(pc, NodeTypeSuspend, suspend_token);
682 node->data.suspend.promise_symbol = ast_parse_symbol(pc, token_index);
683 ast_eat_token(pc, token_index, TokenIdBinOr);
684 node->data.suspend.block = ast_parse_block(pc, token_index, true);
685
686 return node;
687}
688
653689/*
654690CompTimeExpression(body) = "comptime" body
655691*/
......@@ -674,7 +710,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
674710
675711/*
676712PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
677KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
713KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable" | "suspend"
678714ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
679715*/
680716static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
......@@ -738,6 +774,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
738774 AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
739775 *token_index += 1;
740776 return node;
777 } else if (token->id == TokenIdKeywordSuspend) {
778 AstNode *node = ast_create_node(pc, NodeTypeSuspend, token);
779 *token_index += 1;
780 return node;
741781 } else if (token->id == TokenIdKeywordError) {
742782 Token *next_token = &pc->tokens->at(*token_index + 1);
743783 if (next_token->id == TokenIdLBrace) {
......@@ -920,7 +960,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, size_t *token_inde
920960}
921961
922962/*
923SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
963SuffixOpExpression = ("async" option("(" Expression ")") PrimaryExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
924964FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
925965ArrayAccessExpression : token(LBracket) Expression token(RBracket)
926966SliceExpression = "[" Expression ".." option(Expression) "]"
......@@ -928,9 +968,34 @@ FieldAccessExpression : token(Dot) token(Symbol)
928968StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
929969*/
930970static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
931 AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
932 if (!primary_expr)
933 return nullptr;
971 AstNode *primary_expr;
972
973 Token *async_token = &pc->tokens->at(*token_index);
974 if (async_token->id == TokenIdKeywordAsync) {
975 *token_index += 1;
976
977 AstNode *allocator_expr_node = nullptr;
978 Token *async_lparen_tok = &pc->tokens->at(*token_index);
979 if (async_lparen_tok->id == TokenIdLParen) {
980 *token_index += 1;
981 allocator_expr_node = ast_parse_expression(pc, token_index, true);
982 ast_eat_token(pc, token_index, TokenIdRParen);
983 }
984
985 AstNode *fn_ref_expr_node = ast_parse_primary_expr(pc, token_index, true);
986 Token *lparen_tok = ast_eat_token(pc, token_index, TokenIdLParen);
987 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, lparen_tok);
988 node->data.fn_call_expr.is_async = true;
989 node->data.fn_call_expr.async_allocator = allocator_expr_node;
990 node->data.fn_call_expr.fn_ref_expr = fn_ref_expr_node;
991 ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
992
993 primary_expr = node;
994 } else {
995 primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
996 if (!primary_expr)
997 return nullptr;
998 }
934999
9351000 while (true) {
9361001 Token *first_token = &pc->tokens->at(*token_index);
......@@ -1042,7 +1107,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
10421107
10431108/*
10441109PrefixOpExpression = PrefixOp ErrorSetExpr | SuffixOpExpression
1045PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
1110PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
10461111*/
10471112static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
10481113 Token *token = &pc->tokens->at(*token_index);
......@@ -1052,6 +1117,9 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index,
10521117 if (token->id == TokenIdKeywordTry) {
10531118 return ast_parse_try_expr(pc, token_index);
10541119 }
1120 if (token->id == TokenIdKeywordAwait) {
1121 return ast_parse_await_expr(pc, token_index);
1122 }
10551123 PrefixOp prefix_op = tok_to_prefix_op(token);
10561124 if (prefix_op == PrefixOpInvalid) {
10571125 return ast_parse_suffix_op_expr(pc, token_index, mandatory);
......@@ -1510,6 +1578,23 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index) {
15101578 return node;
15111579}
15121580
1581/*
1582AwaitExpression : "await" Expression
1583*/
1584static AstNode *ast_parse_await_expr(ParseContext *pc, size_t *token_index) {
1585 Token *token = &pc->tokens->at(*token_index);
1586
1587 if (token->id != TokenIdKeywordAwait) {
1588 return nullptr;
1589 }
1590 *token_index += 1;
1591
1592 AstNode *node = ast_create_node(pc, NodeTypeAwaitExpr, token);
1593 node->data.await_expr.expr = ast_parse_expression(pc, token_index, true);
1594
1595 return node;
1596}
1597
15131598/*
15141599BreakExpression = "break" option(":" Symbol) option(Expression)
15151600*/
......@@ -1535,6 +1620,42 @@ static AstNode *ast_parse_break_expr(ParseContext *pc, size_t *token_index) {
15351620 return node;
15361621}
15371622
1623/*
1624CancelExpression = "cancel" Expression;
1625*/
1626static AstNode *ast_parse_cancel_expr(ParseContext *pc, size_t *token_index) {
1627 Token *token = &pc->tokens->at(*token_index);
1628
1629 if (token->id != TokenIdKeywordCancel) {
1630 return nullptr;
1631 }
1632 *token_index += 1;
1633
1634 AstNode *node = ast_create_node(pc, NodeTypeCancel, token);
1635
1636 node->data.cancel_expr.expr = ast_parse_expression(pc, token_index, false);
1637
1638 return node;
1639}
1640
1641/*
1642ResumeExpression = "resume" Expression;
1643*/
1644static AstNode *ast_parse_resume_expr(ParseContext *pc, size_t *token_index) {
1645 Token *token = &pc->tokens->at(*token_index);
1646
1647 if (token->id != TokenIdKeywordResume) {
1648 return nullptr;
1649 }
1650 *token_index += 1;
1651
1652 AstNode *node = ast_create_node(pc, NodeTypeResume, token);
1653
1654 node->data.resume_expr.expr = ast_parse_expression(pc, token_index, false);
1655
1656 return node;
1657}
1658
15381659/*
15391660Defer(body) = ("defer" | "errdefer") body
15401661*/
......@@ -2001,7 +2122,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, size_t *token_index, boo
20012122}
20022123
20032124/*
2004BlockExpression(body) = Block | IfExpression(body) | TryExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body)
2125BlockExpression(body) = Block | IfExpression(body) | IfErrorExpression(body) | TestExpression(body) | WhileExpression(body) | ForExpression(body) | SwitchExpression | CompTimeExpression(body) | SuspendExpression(body)
20052126*/
20062127static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
20072128 Token *token = &pc->tokens->at(*token_index);
......@@ -2030,6 +2151,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, size_t *token_index, bool
20302151 if (comptime_node)
20312152 return comptime_node;
20322153
2154 AstNode *suspend_node = ast_parse_suspend_block(pc, token_index, false);
2155 if (suspend_node)
2156 return suspend_node;
2157
20332158 if (mandatory)
20342159 ast_invalid_token_error(pc, token);
20352160
......@@ -2159,7 +2284,7 @@ static AstNode *ast_parse_block_or_expression(ParseContext *pc, size_t *token_in
21592284}
21602285
21612286/*
2162Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression
2287Expression = TryExpression | ReturnExpression | BreakExpression | AssignmentExpression | CancelExpression | ResumeExpression
21632288*/
21642289static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool mandatory) {
21652290 Token *token = &pc->tokens->at(*token_index);
......@@ -2176,6 +2301,14 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
21762301 if (break_expr)
21772302 return break_expr;
21782303
2304 AstNode *cancel_expr = ast_parse_cancel_expr(pc, token_index);
2305 if (cancel_expr)
2306 return cancel_expr;
2307
2308 AstNode *resume_expr = ast_parse_resume_expr(pc, token_index);
2309 if (resume_expr)
2310 return resume_expr;
2311
21792312 AstNode *ass_expr = ast_parse_ass_expr(pc, token_index, false);
21802313 if (ass_expr)
21812314 return ass_expr;
......@@ -2208,6 +2341,8 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
22082341 return node->data.comptime_expr.expr->type == NodeTypeBlock;
22092342 case NodeTypeDefer:
22102343 return node->data.defer.expr->type == NodeTypeBlock;
2344 case NodeTypeSuspend:
2345 return node->data.suspend.block != nullptr && node->data.suspend.block->type == NodeTypeBlock;
22112346 case NodeTypeSwitchExpr:
22122347 case NodeTypeBlock:
22132348 return true;
......@@ -2286,7 +2421,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
22862421}
22872422
22882423/*
2289FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
2424FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
22902425*/
22912426static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
22922427 Token *first_token = &pc->tokens->at(*token_index);
......@@ -2294,10 +2429,20 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
22942429
22952430 CallingConvention cc;
22962431 bool is_extern = false;
2432 AstNode *async_allocator_type_node = nullptr;
22972433 if (first_token->id == TokenIdKeywordNakedCC) {
22982434 *token_index += 1;
22992435 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
23002436 cc = CallingConventionNaked;
2437 } else if (first_token->id == TokenIdKeywordAsync) {
2438 *token_index += 1;
2439 Token *next_token = &pc->tokens->at(*token_index);
2440 if (next_token->id == TokenIdLParen) {
2441 async_allocator_type_node = ast_parse_type_expr(pc, token_index, true);
2442 ast_eat_token(pc, token_index, TokenIdRParen);
2443 }
2444 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2445 cc = CallingConventionAsync;
23012446 } else if (first_token->id == TokenIdKeywordStdcallCC) {
23022447 *token_index += 1;
23032448 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
......@@ -2332,6 +2477,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
23322477 node->data.fn_proto.visib_mod = visib_mod;
23332478 node->data.fn_proto.cc = cc;
23342479 node->data.fn_proto.is_extern = is_extern;
2480 node->data.fn_proto.async_allocator_type = async_allocator_type_node;
23352481
23362482 Token *fn_name = &pc->tokens->at(*token_index);
23372483
......@@ -2747,6 +2893,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
27472893 visit_node_list(&node->data.fn_proto.params, visit, context);
27482894 visit_field(&node->data.fn_proto.align_expr, visit, context);
27492895 visit_field(&node->data.fn_proto.section_expr, visit, context);
2896 visit_field(&node->data.fn_proto.async_allocator_type, visit, context);
27502897 break;
27512898 case NodeTypeFnDef:
27522899 visit_field(&node->data.fn_def.fn_proto, visit, context);
......@@ -2809,6 +2956,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
28092956 case NodeTypeFnCallExpr:
28102957 visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context);
28112958 visit_node_list(&node->data.fn_call_expr.params, visit, context);
2959 visit_field(&node->data.fn_call_expr.async_allocator, visit, context);
28122960 break;
28132961 case NodeTypeArrayAccessExpr:
28142962 visit_field(&node->data.array_access_expr.array_ref_expr, visit, context);
......@@ -2931,5 +3079,18 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
29313079 case NodeTypeErrorSetDecl:
29323080 visit_node_list(&node->data.err_set_decl.decls, visit, context);
29333081 break;
3082 case NodeTypeCancel:
3083 visit_field(&node->data.cancel_expr.expr, visit, context);
3084 break;
3085 case NodeTypeResume:
3086 visit_field(&node->data.resume_expr.expr, visit, context);
3087 break;
3088 case NodeTypeAwaitExpr:
3089 visit_field(&node->data.await_expr.expr, visit, context);
3090 break;
3091 case NodeTypeSuspend:
3092 visit_field(&node->data.suspend.promise_symbol, visit, context);
3093 visit_field(&node->data.suspend.block, visit, context);
3094 break;
29343095 }
29353096}
src/tokenizer.cpp+10
......@@ -110,7 +110,10 @@ static const struct ZigKeyword zig_keywords[] = {
110110 {"align", TokenIdKeywordAlign},
111111 {"and", TokenIdKeywordAnd},
112112 {"asm", TokenIdKeywordAsm},
113 {"async", TokenIdKeywordAsync},
114 {"await", TokenIdKeywordAwait},
113115 {"break", TokenIdKeywordBreak},
116 {"cancel", TokenIdKeywordCancel},
114117 {"catch", TokenIdKeywordCatch},
115118 {"comptime", TokenIdKeywordCompTime},
116119 {"const", TokenIdKeywordConst},
......@@ -133,10 +136,12 @@ static const struct ZigKeyword zig_keywords[] = {
133136 {"or", TokenIdKeywordOr},
134137 {"packed", TokenIdKeywordPacked},
135138 {"pub", TokenIdKeywordPub},
139 {"resume", TokenIdKeywordResume},
136140 {"return", TokenIdKeywordReturn},
137141 {"section", TokenIdKeywordSection},
138142 {"stdcallcc", TokenIdKeywordStdcallCC},
139143 {"struct", TokenIdKeywordStruct},
144 {"suspend", TokenIdKeywordSuspend},
140145 {"switch", TokenIdKeywordSwitch},
141146 {"test", TokenIdKeywordTest},
142147 {"this", TokenIdKeywordThis},
......@@ -1523,6 +1528,11 @@ const char * token_name(TokenId id) {
15231528 case TokenIdFatArrow: return "=>";
15241529 case TokenIdFloatLiteral: return "FloatLiteral";
15251530 case TokenIdIntLiteral: return "IntLiteral";
1531 case TokenIdKeywordAsync: return "async";
1532 case TokenIdKeywordAwait: return "await";
1533 case TokenIdKeywordResume: return "resume";
1534 case TokenIdKeywordSuspend: return "suspend";
1535 case TokenIdKeywordCancel: return "cancel";
15261536 case TokenIdKeywordAlign: return "align";
15271537 case TokenIdKeywordAnd: return "and";
15281538 case TokenIdKeywordAsm: return "asm";
src/tokenizer.hpp+5
......@@ -51,7 +51,10 @@ enum TokenId {
5151 TokenIdKeywordAlign,
5252 TokenIdKeywordAnd,
5353 TokenIdKeywordAsm,
54 TokenIdKeywordAsync,
55 TokenIdKeywordAwait,
5456 TokenIdKeywordBreak,
57 TokenIdKeywordCancel,
5558 TokenIdKeywordCatch,
5659 TokenIdKeywordCompTime,
5760 TokenIdKeywordConst,
......@@ -74,10 +77,12 @@ enum TokenId {
7477 TokenIdKeywordOr,
7578 TokenIdKeywordPacked,
7679 TokenIdKeywordPub,
80 TokenIdKeywordResume,
7781 TokenIdKeywordReturn,
7882 TokenIdKeywordSection,
7983 TokenIdKeywordStdcallCC,
8084 TokenIdKeywordStruct,
85 TokenIdKeywordSuspend,
8186 TokenIdKeywordSwitch,
8287 TokenIdKeywordTest,
8388 TokenIdKeywordThis,
src/zig_llvm.cpp+6
......@@ -32,6 +32,7 @@
3232#include <llvm/Support/TargetParser.h>
3333#include <llvm/Support/raw_ostream.h>
3434#include <llvm/Target/TargetMachine.h>
35#include <llvm/Transforms/Coroutines.h>
3536#include <llvm/Transforms/IPO.h>
3637#include <llvm/Transforms/IPO/PassManagerBuilder.h>
3738#include <llvm/Transforms/IPO/AlwaysInliner.h>
......@@ -129,6 +130,8 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
129130 PMBuilder->Inliner = createFunctionInliningPass(PMBuilder->OptLevel, PMBuilder->SizeLevel, false);
130131 }
131132
133 addCoroutinePassesToExtensionPoints(*PMBuilder);
134
132135 // Set up the per-function pass manager.
133136 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
134137 auto tliwp = new(std::nothrow) TargetLibraryInfoWrapperPass(tlii);
......@@ -182,6 +185,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
182185 return false;
183186}
184187
188ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref) {
189 return wrap(Type::getTokenTy(*unwrap(context_ref)));
190}
185191
186192LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
187193 unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name)
src/zig_llvm.h+2
......@@ -54,6 +54,8 @@ enum ZigLLVM_EmitOutputType {
5454ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
5555 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
5656
57ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
58
5759enum ZigLLVM_FnInline {
5860 ZigLLVM_FnInlineAuto,
5961 ZigLLVM_FnInlineAlways,
std/debug/index.zig+8-10
......@@ -98,21 +98,18 @@ pub fn assertOrPanic(ok: bool) void {
9898 }
9999}
100100
101var panicking = false;
101var panicking: u8 = 0; // TODO make this a bool
102102/// This is the default panic implementation.
103103pub fn panic(comptime format: []const u8, args: ...) noreturn {
104 // TODO an intrinsic that labels this as unlikely to be reached
104 @setCold(true);
105105
106 // TODO
107 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
108 if (panicking) {
106 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
109107 // Panicked during a panic.
108
110109 // TODO detect if a different thread caused the panic, because in that case
111110 // we would want to return here instead of calling abort, so that the thread
112111 // which first called panic can finish printing a stack trace.
113112 os.abort();
114 } else {
115 panicking = true;
116113 }
117114
118115 const stderr = getStderrStream() catch os.abort();
......@@ -123,10 +120,11 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
123120}
124121
125122pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
126 if (panicking) {
123 @setCold(true);
124
125 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
126 // See TODO in above function
127127 os.abort();
128 } else {
129 panicking = true;
130128 }
131129 const stderr = getStderrStream() catch os.abort();
132130 stderr.print(format ++ "\n", args) catch os.abort();
std/hash_map.zig+1-1
......@@ -235,7 +235,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
235235 };
236236}
237237
238test "basicHashMapTest" {
238test "basic hash map usage" {
239239 var map = HashMap(i32, i32, hash_i32, eql_i32).init(debug.global_allocator);
240240 defer map.deinit();
241241
std/os/child_process.zig-50
......@@ -32,9 +32,6 @@ pub const ChildProcess = struct {
3232
3333 pub argv: []const []const u8,
3434
35 /// Possibly called from a signal handler. Must set this before calling `spawn`.
36 pub onTerm: ?fn(&ChildProcess)void,
37
3835 /// Leave as null to use the current env map using the supplied allocator.
3936 pub env_map: ?&const BufMap,
4037
......@@ -102,7 +99,6 @@ pub const ChildProcess = struct {
10299 .err_pipe = undefined,
103100 .llnode = undefined,
104101 .term = null,
105 .onTerm = null,
106102 .env_map = null,
107103 .cwd = null,
108104 .uid = if (is_windows) {} else null,
......@@ -124,7 +120,6 @@ pub const ChildProcess = struct {
124120 self.gid = user_info.gid;
125121 }
126122
127 /// onTerm can be called before `spawn` returns.
128123 /// On success must call `kill` or `wait`.
129124 pub fn spawn(self: &ChildProcess) !void {
130125 if (is_windows) {
......@@ -165,9 +160,6 @@ pub const ChildProcess = struct {
165160 }
166161
167162 pub fn killPosix(self: &ChildProcess) !Term {
168 block_SIGCHLD();
169 defer restore_SIGCHLD();
170
171163 if (self.term) |term| {
172164 self.cleanupStreams();
173165 return term;
......@@ -246,9 +238,6 @@ pub const ChildProcess = struct {
246238 }
247239
248240 fn waitPosix(self: &ChildProcess) !Term {
249 block_SIGCHLD();
250 defer restore_SIGCHLD();
251
252241 if (self.term) |term| {
253242 self.cleanupStreams();
254243 return term;
......@@ -298,10 +287,6 @@ pub const ChildProcess = struct {
298287
299288 fn handleWaitResult(self: &ChildProcess, status: i32) void {
300289 self.term = self.cleanupAfterWait(status);
301
302 if (self.onTerm) |onTerm| {
303 onTerm(self);
304 }
305290 }
306291
307292 fn cleanupStreams(self: &ChildProcess) void {
......@@ -347,9 +332,6 @@ pub const ChildProcess = struct {
347332 }
348333
349334 fn spawnPosix(self: &ChildProcess) !void {
350 // TODO atomically set a flag saying that we already did this
351 install_SIGCHLD_handler();
352
353335 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
354336 errdefer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
355337
......@@ -387,11 +369,9 @@ pub const ChildProcess = struct {
387369 const err_pipe = try makePipe();
388370 errdefer destroyPipe(err_pipe);
389371
390 block_SIGCHLD();
391372 const pid_result = posix.fork();
392373 const pid_err = posix.getErrno(pid_result);
393374 if (pid_err > 0) {
394 restore_SIGCHLD();
395375 return switch (pid_err) {
396376 posix.EAGAIN, posix.ENOMEM, posix.ENOSYS => error.SystemResources,
397377 else => os.unexpectedErrorPosix(pid_err),
......@@ -399,7 +379,6 @@ pub const ChildProcess = struct {
399379 }
400380 if (pid_result == 0) {
401381 // we are the child
402 restore_SIGCHLD();
403382
404383 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch
405384 |err| forkChildErrReport(err_pipe[1], err);
......@@ -451,8 +430,6 @@ pub const ChildProcess = struct {
451430 // TODO make this atomic so it works even with threads
452431 children_nodes.prepend(&self.llnode);
453432
454 restore_SIGCHLD();
455
456433 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
457434 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
458435 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
......@@ -824,30 +801,3 @@ fn handleTerm(pid: i32, status: i32) void {
824801 }
825802 }
826803}
827
828const sigchld_set = x: {
829 var signal_set = posix.empty_sigset;
830 posix.sigaddset(&signal_set, posix.SIGCHLD);
831 break :x signal_set;
832};
833
834fn block_SIGCHLD() void {
835 const err = posix.getErrno(posix.sigprocmask(posix.SIG_BLOCK, &sigchld_set, null));
836 assert(err == 0);
837}
838
839fn restore_SIGCHLD() void {
840 const err = posix.getErrno(posix.sigprocmask(posix.SIG_UNBLOCK, &sigchld_set, null));
841 assert(err == 0);
842}
843
844const sigchld_action = posix.Sigaction {
845 .handler = sigchld_handler,
846 .mask = posix.empty_sigset,
847 .flags = posix.SA_RESTART | posix.SA_NOCLDSTOP,
848};
849
850fn install_SIGCHLD_handler() void {
851 const err = posix.getErrno(posix.sigaction(posix.SIGCHLD, &sigchld_action, null));
852 assert(err == 0);
853}
std/unicode.zig+140-9
......@@ -1,4 +1,5 @@
11const std = @import("./index.zig");
2const debug = std.debug;
23
34/// Given the first byte of a UTF-8 codepoint,
45/// returns a number 1-4 indicating the total length of the codepoint in bytes.
......@@ -25,8 +26,8 @@ pub fn utf8Decode(bytes: []const u8) !u32 {
2526 };
2627}
2728pub fn utf8Decode2(bytes: []const u8) !u32 {
28 std.debug.assert(bytes.len == 2);
29 std.debug.assert(bytes[0] & 0b11100000 == 0b11000000);
29 debug.assert(bytes.len == 2);
30 debug.assert(bytes[0] & 0b11100000 == 0b11000000);
3031 var value: u32 = bytes[0] & 0b00011111;
3132
3233 if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation;
......@@ -38,8 +39,8 @@ pub fn utf8Decode2(bytes: []const u8) !u32 {
3839 return value;
3940}
4041pub fn utf8Decode3(bytes: []const u8) !u32 {
41 std.debug.assert(bytes.len == 3);
42 std.debug.assert(bytes[0] & 0b11110000 == 0b11100000);
42 debug.assert(bytes.len == 3);
43 debug.assert(bytes[0] & 0b11110000 == 0b11100000);
4344 var value: u32 = bytes[0] & 0b00001111;
4445
4546 if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation;
......@@ -56,8 +57,8 @@ pub fn utf8Decode3(bytes: []const u8) !u32 {
5657 return value;
5758}
5859pub fn utf8Decode4(bytes: []const u8) !u32 {
59 std.debug.assert(bytes.len == 4);
60 std.debug.assert(bytes[0] & 0b11111000 == 0b11110000);
60 debug.assert(bytes.len == 4);
61 debug.assert(bytes[0] & 0b11111000 == 0b11110000);
6162 var value: u32 = bytes[0] & 0b00000111;
6263
6364 if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation;
......@@ -78,6 +79,136 @@ pub fn utf8Decode4(bytes: []const u8) !u32 {
7879 return value;
7980}
8081
82pub fn utf8ValidateSlice(s: []const u8) bool {
83 var i: usize = 0;
84 while (i < s.len) {
85 if (utf8ByteSequenceLength(s[i])) |cp_len| {
86 if (i + cp_len > s.len) {
87 return false;
88 }
89
90 if (utf8Decode(s[i..i+cp_len])) |_| {} else |_| { return false; }
91 i += cp_len;
92 } else |err| {
93 return false;
94 }
95 }
96 return true;
97}
98
99const Utf8View = struct {
100 bytes: []const u8,
101
102 pub fn init(s: []const u8) !Utf8View {
103 if (!utf8ValidateSlice(s)) {
104 return error.InvalidUtf8;
105 }
106
107 return initUnchecked(s);
108 }
109
110 pub fn initUnchecked(s: []const u8) Utf8View {
111 return Utf8View {
112 .bytes = s,
113 };
114 }
115
116 pub fn initComptime(comptime s: []const u8) Utf8View {
117 if (comptime init(s)) |r| {
118 return r;
119 } else |err| switch (err) {
120 error.InvalidUtf8 => {
121 @compileError("invalid utf8");
122 unreachable;
123 }
124 }
125 }
126
127 pub fn Iterator(s: &const Utf8View) Utf8Iterator {
128 return Utf8Iterator {
129 .bytes = s.bytes,
130 .i = 0,
131 };
132 }
133};
134
135const Utf8Iterator = struct {
136 bytes: []const u8,
137 i: usize,
138
139 pub fn nextCodepointSlice(it: &Utf8Iterator) ?[]const u8 {
140 if (it.i >= it.bytes.len) {
141 return null;
142 }
143
144 const cp_len = utf8ByteSequenceLength(it.bytes[it.i]) catch unreachable;
145
146 it.i += cp_len;
147 return it.bytes[it.i-cp_len..it.i];
148 }
149
150 pub fn nextCodepoint(it: &Utf8Iterator) ?u32 {
151 const slice = it.nextCodepointSlice() ?? return null;
152
153 const r = switch (slice.len) {
154 1 => u32(slice[0]),
155 2 => utf8Decode2(slice),
156 3 => utf8Decode3(slice),
157 4 => utf8Decode4(slice),
158 else => unreachable,
159 };
160
161 return r catch unreachable;
162 }
163};
164
165test "utf8 iterator on ascii" {
166 const s = Utf8View.initComptime("abc");
167
168 var it1 = s.Iterator();
169 debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice()));
170 debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice()));
171 debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice()));
172 debug.assert(it1.nextCodepointSlice() == null);
173
174 var it2 = s.Iterator();
175 debug.assert(??it2.nextCodepoint() == 'a');
176 debug.assert(??it2.nextCodepoint() == 'b');
177 debug.assert(??it2.nextCodepoint() == 'c');
178 debug.assert(it2.nextCodepoint() == null);
179}
180
181test "utf8 view bad" {
182 // Compile-time error.
183 // const s3 = Utf8View.initComptime("\xfe\xf2");
184
185 const s = Utf8View.init("hel\xadlo");
186 if (s) |_| { unreachable; } else |err| { debug.assert(err == error.InvalidUtf8); }
187}
188
189test "utf8 view ok" {
190 const s = Utf8View.initComptime("東京市");
191
192 var it1 = s.Iterator();
193 debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice()));
194 debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice()));
195 debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice()));
196 debug.assert(it1.nextCodepointSlice() == null);
197
198 var it2 = s.Iterator();
199 debug.assert(??it2.nextCodepoint() == 0x6771);
200 debug.assert(??it2.nextCodepoint() == 0x4eac);
201 debug.assert(??it2.nextCodepoint() == 0x5e02);
202 debug.assert(it2.nextCodepoint() == null);
203}
204
205test "bad utf8 slice" {
206 debug.assert(utf8ValidateSlice("abc"));
207 debug.assert(!utf8ValidateSlice("abc\xc0"));
208 debug.assert(!utf8ValidateSlice("abc\xc0abc"));
209 debug.assert(utf8ValidateSlice("abc\xdf\xbf"));
210}
211
81212test "valid utf8" {
82213 testValid("\x00", 0x0);
83214 testValid("\x20", 0x20);
......@@ -145,17 +276,17 @@ fn testError(bytes: []const u8, expected_err: error) void {
145276 if (testDecode(bytes)) |_| {
146277 unreachable;
147278 } else |err| {
148 std.debug.assert(err == expected_err);
279 debug.assert(err == expected_err);
149280 }
150281}
151282
152283fn testValid(bytes: []const u8, expected_codepoint: u32) void {
153 std.debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint);
284 debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint);
154285}
155286
156287fn testDecode(bytes: []const u8) !u32 {
157288 const length = try utf8ByteSequenceLength(bytes[0]);
158289 if (bytes.len < length) return error.UnexpectedEof;
159 std.debug.assert(bytes.len == length);
290 debug.assert(bytes.len == length);
160291 return utf8Decode(bytes);
161292}
test/behavior.zig+14-1
......@@ -1,3 +1,5 @@
1const builtin = @import("builtin");
2
13comptime {
24 _ = @import("cases/align.zig");
35 _ = @import("cases/alignof.zig");
......@@ -34,8 +36,8 @@ comptime {
3436 _ = @import("cases/sizeof_and_typeof.zig");
3537 _ = @import("cases/slice.zig");
3638 _ = @import("cases/struct.zig");
37 _ = @import("cases/struct_contains_slice_of_itself.zig");
3839 _ = @import("cases/struct_contains_null_ptr_itself.zig");
40 _ = @import("cases/struct_contains_slice_of_itself.zig");
3941 _ = @import("cases/switch.zig");
4042 _ = @import("cases/switch_prong_err_enum.zig");
4143 _ = @import("cases/switch_prong_implicit_cast.zig");
......@@ -47,4 +49,15 @@ comptime {
4749 _ = @import("cases/var_args.zig");
4850 _ = @import("cases/void.zig");
4951 _ = @import("cases/while.zig");
52
53
54 // LLVM 5.0.1, 6.0.0, and trunk crash when attempting to optimize coroutine code.
55 // So, Zig does not support ReleaseFast or ReleaseSafe for coroutines yet.
56 // Luckily, Clang users are running into the same crashes, so folks from the LLVM
57 // community are working on fixes. If we're really lucky they'll be fixed in 6.0.1.
58 // Otherwise we can hope for 7.0.0.
59 if (builtin.mode == builtin.Mode.Debug) {
60 _ = @import("cases/coroutines.zig");
61 }
62
5063}
test/cases/atomics.zig+14-1
......@@ -1,5 +1,7 @@
11const assert = @import("std").debug.assert;
2const AtomicOrder = @import("builtin").AtomicOrder;
2const builtin = @import("builtin");
3const AtomicRmwOp = builtin.AtomicRmwOp;
4const AtomicOrder = builtin.AtomicOrder;
35
46test "cmpxchg" {
57 var x: i32 = 1234;
......@@ -12,3 +14,14 @@ test "fence" {
1214 @fence(AtomicOrder.SeqCst);
1315 x = 5678;
1416}
17
18test "atomicrmw" {
19 var data: u8 = 200;
20 testAtomicRmw(&data);
21 assert(data == 42);
22}
23
24fn testAtomicRmw(ptr: &u8) void {
25 const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
26 assert(prev_value == 200);
27}
test/cases/cast.zig+102
......@@ -32,6 +32,108 @@ fn funcWithConstPtrPtr(x: &const &i32) void {
3232 **x += 1;
3333}
3434
35test "implicitly cast a container to a const pointer of it" {
36 const z = Struct(void) { .x = void{} };
37 assert(0 == @sizeOf(@typeOf(z)));
38 assert(void{} == Struct(void).pointer(z).x);
39 assert(void{} == Struct(void).pointer(&z).x);
40 assert(void{} == Struct(void).maybePointer(z).x);
41 assert(void{} == Struct(void).maybePointer(&z).x);
42 assert(void{} == Struct(void).maybePointer(null).x);
43 const s = Struct(u8) { .x = 42 };
44 assert(0 != @sizeOf(@typeOf(s)));
45 assert(42 == Struct(u8).pointer(s).x);
46 assert(42 == Struct(u8).pointer(&s).x);
47 assert(42 == Struct(u8).maybePointer(s).x);
48 assert(42 == Struct(u8).maybePointer(&s).x);
49 assert(0 == Struct(u8).maybePointer(null).x);
50 const u = Union { .x = 42 };
51 assert(42 == Union.pointer(u).x);
52 assert(42 == Union.pointer(&u).x);
53 assert(42 == Union.maybePointer(u).x);
54 assert(42 == Union.maybePointer(&u).x);
55 assert(0 == Union.maybePointer(null).x);
56 const e = Enum.Some;
57 assert(Enum.Some == Enum.pointer(e));
58 assert(Enum.Some == Enum.pointer(&e));
59 assert(Enum.Some == Enum.maybePointer(e));
60 assert(Enum.Some == Enum.maybePointer(&e));
61 assert(Enum.None == Enum.maybePointer(null));
62}
63
64fn Struct(comptime T: type) type {
65 return struct {
66 const Self = this;
67 x: T,
68
69 fn pointer(self: &const Self) Self {
70 return *self;
71 }
72
73 fn maybePointer(self: ?&const Self) Self {
74 const none = Self { .x = if (T == void) void{} else 0 };
75 return *(self ?? &none);
76 }
77 };
78}
79
80const Union = union {
81 x: u8,
82
83 fn pointer(self: &const Union) Union {
84 return *self;
85 }
86
87 fn maybePointer(self: ?&const Union) Union {
88 const none = Union { .x = 0 };
89 return *(self ?? &none);
90 }
91};
92
93const Enum = enum {
94 None,
95 Some,
96
97 fn pointer(self: &const Enum) Enum {
98 return *self;
99 }
100
101 fn maybePointer(self: ?&const Enum) Enum {
102 return *(self ?? &Enum.None);
103 }
104};
105
106test "implicitly cast indirect pointer to maybe-indirect pointer" {
107 const S = struct {
108 const Self = this;
109 x: u8,
110 fn constConst(p: &const &const Self) u8 {
111 return (*p).x;
112 }
113 fn maybeConstConst(p: ?&const &const Self) u8 {
114 return (*??p).x;
115 }
116 fn constConstConst(p: &const &const &const Self) u8 {
117 return (**p).x;
118 }
119 fn maybeConstConstConst(p: ?&const &const &const Self) u8 {
120 return (**??p).x;
121 }
122 };
123 const s = S { .x = 42 };
124 const p = &s;
125 const q = &p;
126 const r = &q;
127 assert(42 == S.constConst(p));
128 assert(42 == S.constConst(q));
129 assert(42 == S.maybeConstConst(p));
130 assert(42 == S.maybeConstConst(q));
131 assert(42 == S.constConstConst(q));
132 assert(42 == S.constConstConst(r));
133 assert(42 == S.maybeConstConstConst(q));
134 assert(42 == S.maybeConstConstConst(r));
135}
136
35137test "explicit cast from integer to error type" {
36138 testCastIntToErr(error.ItBroke);
37139 comptime testCastIntToErr(error.ItBroke);
test/cases/coroutines.zig created+132
......@@ -0,0 +1,132 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4var x: i32 = 1;
5
6test "create a coroutine and cancel it" {
7 const p = try async(std.debug.global_allocator) simpleAsyncFn();
8 cancel p;
9 assert(x == 2);
10}
11
12async fn simpleAsyncFn() void {
13 x += 1;
14 suspend;
15 x += 1;
16}
17
18test "coroutine suspend, resume, cancel" {
19 seq('a');
20 const p = try async(std.debug.global_allocator) testAsyncSeq();
21 seq('c');
22 resume p;
23 seq('f');
24 cancel p;
25 seq('g');
26
27 assert(std.mem.eql(u8, points, "abcdefg"));
28}
29
30async fn testAsyncSeq() void {
31 defer seq('e');
32
33 seq('b');
34 suspend;
35 seq('d');
36}
37var points = []u8{0} ** "abcdefg".len;
38var index: usize = 0;
39
40fn seq(c: u8) void {
41 points[index] = c;
42 index += 1;
43}
44
45test "coroutine suspend with block" {
46 const p = try async(std.debug.global_allocator) testSuspendBlock();
47 std.debug.assert(!result);
48 resume a_promise;
49 std.debug.assert(result);
50 cancel p;
51}
52
53var a_promise: promise = undefined;
54var result = false;
55
56async fn testSuspendBlock() void {
57 suspend |p| {
58 a_promise = p;
59 }
60 result = true;
61}
62
63var await_a_promise: promise = undefined;
64var await_final_result: i32 = 0;
65
66test "coroutine await" {
67 await_seq('a');
68 const p = async(std.debug.global_allocator) await_amain() catch unreachable;
69 await_seq('f');
70 resume await_a_promise;
71 await_seq('i');
72 assert(await_final_result == 1234);
73 assert(std.mem.eql(u8, await_points, "abcdefghi"));
74}
75
76async fn await_amain() void {
77 await_seq('b');
78 const p = async await_another() catch unreachable;
79 await_seq('e');
80 await_final_result = await p;
81 await_seq('h');
82}
83
84async fn await_another() i32 {
85 await_seq('c');
86 suspend |p| {
87 await_seq('d');
88 await_a_promise = p;
89 }
90 await_seq('g');
91 return 1234;
92}
93
94var await_points = []u8{0} ** "abcdefghi".len;
95var await_seq_index: usize = 0;
96
97fn await_seq(c: u8) void {
98 await_points[await_seq_index] = c;
99 await_seq_index += 1;
100}
101
102
103var early_final_result: i32 = 0;
104
105test "coroutine await early return" {
106 early_seq('a');
107 const p = async(std.debug.global_allocator) early_amain() catch unreachable;
108 early_seq('f');
109 assert(early_final_result == 1234);
110 assert(std.mem.eql(u8, early_points, "abcdef"));
111}
112
113async fn early_amain() void {
114 early_seq('b');
115 const p = async early_another() catch unreachable;
116 early_seq('d');
117 early_final_result = await p;
118 early_seq('e');
119}
120
121async fn early_another() i32 {
122 early_seq('c');
123 return 1234;
124}
125
126var early_points = []u8{0} ** "abcdef".len;
127var early_seq_index: usize = 0;
128
129fn early_seq(c: u8) void {
130 early_points[early_seq_index] = c;
131 early_seq_index += 1;
132}
test/compile_errors.zig+12
......@@ -3090,4 +3090,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
30903090 ,
30913091 ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
30923092 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'");
3093
3094 cases.add("self-referencing function pointer field",
3095 \\const S = struct {
3096 \\ f: fn(_: S) void,
3097 \\};
3098 \\fn f(_: S) void {
3099 \\}
3100 \\export fn entry() void {
3101 \\ var _ = S { .f = f };
3102 \\}
3103 ,
3104 ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value");
30933105}