authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-20 20:47:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-26 15:57:06-07:00
log5a8c445779b3b87ba38fbcac0efcc7ebb3787161
treef83e02739497a46928bb2c7baa36657f486d2294
parent7322aa118376a635ab077ca833dd152639953337

stage2: add call_async ZIR instruction

This is to be used when the source code looks like this: var a = async b(); The instruction acts both as an alloc as well as a function call using that alloc as the result location. This avoids multiple ZIR instructions as well as complicated "inferred pointer" semantic analysis for a common case. AstGen is not yet updated to emit this new instruction.

23 files changed, 510 insertions(+), 98 deletions(-)

src/Air.zig+11
......@@ -310,6 +310,9 @@ pub const Inst = struct {
310310 call_never_tail,
311311 /// Same as `call` except with the `never_inline` attribute.
312312 call_never_inline,
313 /// Async function call.
314 /// Uses `ty_pl` field with the `AsyncCall` payload.
315 call_async,
313316 /// Count leading zeroes of an integer according to its representation in twos complement.
314317 /// Result type will always be an unsigned integer big enough to fit the answer.
315318 /// Uses the `ty_op` field.
......@@ -1070,6 +1073,12 @@ pub const Call = struct {
10701073 args_len: u32,
10711074};
10721075
1076/// Trailing is a list of `Inst.Ref` for every `args_len`.
1077pub const AsyncCall = struct {
1078 callee: Inst.Ref,
1079 args_len: u32,
1080};
1081
10731082/// This data is stored inside extra, with two sets of trailing `Inst.Ref`:
10741083/// * 0. the then body, according to `then_body_len`.
10751084/// * 1. the else body, according to `else_body_len`.
......@@ -1340,6 +1349,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
13401349 .ptr_add,
13411350 .ptr_sub,
13421351 .try_ptr,
1352 .call_async,
13431353 => return air.getRefType(datas[inst].ty_pl.ty),
13441354
13451355 .interned => return ip.typeOf(datas[inst].interned).toType(),
......@@ -1583,6 +1593,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
15831593 .call_always_tail,
15841594 .call_never_tail,
15851595 .call_never_inline,
1596 .call_async,
15861597 .cond_br,
15871598 .switch_br,
15881599 .@"try",
src/AstGen.zig+2-1
......@@ -2788,6 +2788,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27882788 .validate_deref,
27892789 .save_err_ret_index,
27902790 .restore_err_ret_index,
2791 .async_call,
27912792 => break :b true,
27922793
27932794 .@"defer" => unreachable,
......@@ -8701,7 +8702,7 @@ fn builtinCall(
87018702 return rvalue(gz, ri, result, node);
87028703 },
87038704 .async_call => {
8704 const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.AsyncCall{
8705 const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.BuiltinAsyncCall{
87058706 .node = gz.nodeIndexToRelative(node),
87068707 .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]),
87078708 .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
src/InternPool.zig+24
......@@ -209,6 +209,8 @@ pub const Key = union(enum) {
209209 /// `anyframe->T`. The payload is the child type, which may be `none` to indicate
210210 /// `anyframe`.
211211 anyframe_type: Index,
212 /// The payload is the function whose frame it refers to.
213 async_frame_type: Module.Fn.Index,
212214 error_union_type: ErrorUnionType,
213215 simple_type: SimpleType,
214216 /// This represents a struct that has been explicitly declared in source code,
......@@ -711,6 +713,7 @@ pub const Key = union(enum) {
711713 .enum_tag,
712714 .empty_enum_value,
713715 .inferred_error_set_type,
716 .async_frame_type,
714717 .un,
715718 => |x| Hash.hash(seed, asBytes(&x)),
716719
......@@ -930,6 +933,10 @@ pub const Key = union(enum) {
930933 const b_info = b.error_union_type;
931934 return std.meta.eql(a_info, b_info);
932935 },
936 .async_frame_type => |a_info| {
937 const b_info = b.async_frame_type;
938 return a_info == b_info;
939 },
933940 .simple_type => |a_info| {
934941 const b_info = b.simple_type;
935942 return a_info == b_info;
......@@ -1192,6 +1199,7 @@ pub const Key = union(enum) {
11921199 .enum_type,
11931200 .anon_struct_type,
11941201 .func_type,
1202 .async_frame_type,
11951203 => .type_type,
11961204
11971205 inline .runtime_value,
......@@ -1432,6 +1440,7 @@ pub const Index = enum(u32) {
14321440 trailing: struct { names: []NullTerminatedString },
14331441 },
14341442 type_inferred_error_set: struct { data: Module.Fn.InferredErrorSet.Index },
1443 type_async_frame: Module.Fn.Index,
14351444 type_enum_auto: struct {
14361445 const @"data.fields_len" = opaque {};
14371446 data: *EnumAuto,
......@@ -1869,6 +1878,9 @@ pub const Tag = enum(u8) {
18691878 /// An untagged union type which has a safety tag.
18701879 /// `data` is `Module.Union.Index`.
18711880 type_union_safety,
1881 /// The async frame type of a function.
1882 /// data is `Module.Fn.Index`.
1883 type_async_frame,
18721884 /// A function body type.
18731885 /// `data` is extra index to `TypeFunction`.
18741886 type_function,
......@@ -2059,6 +2071,7 @@ pub const Tag = enum(u8) {
20592071 .type_error_union => ErrorUnionType,
20602072 .type_error_set => ErrorSet,
20612073 .type_inferred_error_set => unreachable,
2074 .type_async_frame => unreachable,
20622075 .type_enum_auto => EnumAuto,
20632076 .type_enum_explicit => EnumExplicit,
20642077 .type_enum_nonexhaustive => EnumExplicit,
......@@ -2636,6 +2649,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
26362649 .type_inferred_error_set => .{
26372650 .inferred_error_set_type = @as(Module.Fn.InferredErrorSet.Index, @enumFromInt(data)),
26382651 },
2652 .type_async_frame => .{ .async_frame_type = @enumFromInt(data) },
26392653
26402654 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
26412655 .type_struct => {
......@@ -3240,6 +3254,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
32403254 .data = @intFromEnum(ies_index),
32413255 });
32423256 },
3257 .async_frame_type => |fn_index| {
3258 ip.items.appendAssumeCapacity(.{
3259 .tag = .type_async_frame,
3260 .data = @intFromEnum(fn_index),
3261 });
3262 },
32433263 .simple_type => |simple_type| {
32443264 ip.items.appendAssumeCapacity(.{
32453265 .tag = .simple_type,
......@@ -5053,6 +5073,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
50535073 break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len);
50545074 },
50555075 .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet),
5076 .type_async_frame => 0,
50565077 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
50575078 .type_enum_auto => @sizeOf(EnumAuto),
50585079 .type_opaque => @sizeOf(Key.OpaqueType),
......@@ -5195,6 +5216,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
51955216 .type_error_union,
51965217 .type_error_set,
51975218 .type_inferred_error_set,
5219 .type_async_frame,
51985220 .type_enum_explicit,
51995221 .type_enum_nonexhaustive,
52005222 .type_enum_auto,
......@@ -5578,6 +5600,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
55785600 .type_error_union,
55795601 .type_error_set,
55805602 .type_inferred_error_set,
5603 .type_async_frame,
55815604 .type_enum_auto,
55825605 .type_enum_explicit,
55835606 .type_enum_nonexhaustive,
......@@ -5926,6 +5949,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
59265949 => .Union,
59275950
59285951 .type_function => .Fn,
5952 .type_async_frame => .Frame,
59295953
59305954 // values, not types
59315955 .undef,
src/Liveness.zig+74-39
......@@ -484,28 +484,15 @@ pub fn categorizeOperand(
484484 const inst_data = air_datas[inst].pl_op;
485485 const callee = inst_data.operand;
486486 const extra = air.extraData(Air.Call, inst_data.payload);
487 const args = @as([]const Air.Inst.Ref, @ptrCast(air.extra[extra.end..][0..extra.data.args_len]));
488 if (args.len + 1 <= bpi - 1) {
489 if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
490 for (args, 0..) |arg, i| {
491 if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i + 1)), .write);
492 }
493 return .write;
494 }
495 var bt = l.iterateBigTomb(inst);
496 if (bt.feed()) {
497 if (callee == operand_ref) return .tomb;
498 } else {
499 if (callee == operand_ref) return .write;
500 }
501 for (args) |arg| {
502 if (bt.feed()) {
503 if (arg == operand_ref) return .tomb;
504 } else {
505 if (arg == operand_ref) return .write;
506 }
507 }
508 return .write;
487 const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]);
488 return categorizeOperandCall(l, inst, operand_ref, callee, args);
489 },
490 .call_async => {
491 const inst_data = air_datas[inst].ty_pl;
492 const extra = air.extraData(Air.AsyncCall, inst_data.payload);
493 const callee = extra.data.callee;
494 const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]);
495 return categorizeOperandCall(l, inst, operand_ref, callee, args);
509496 },
510497 .select => {
511498 const pl_op = air_datas[inst].pl_op;
......@@ -674,6 +661,36 @@ pub fn categorizeOperand(
674661 }
675662}
676663
664fn categorizeOperandCall(
665 l: Liveness,
666 inst: Air.Inst.Index,
667 operand_ref: Air.Inst.Ref,
668 callee: Air.Inst.Ref,
669 args: []const Air.Inst.Ref,
670) OperandCategory {
671 if (args.len + 1 <= bpi - 1) {
672 if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
673 for (args, 0..) |arg, i| {
674 if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @intCast(i + 1), .write);
675 }
676 return .write;
677 }
678 var bt = l.iterateBigTomb(inst);
679 if (bt.feed()) {
680 if (callee == operand_ref) return .tomb;
681 } else {
682 if (callee == operand_ref) return .write;
683 }
684 for (args) |arg| {
685 if (bt.feed()) {
686 if (arg == operand_ref) return .tomb;
687 } else {
688 if (arg == operand_ref) return .write;
689 }
690 }
691 return .write;
692}
693
677694fn matchOperandSmallIndex(
678695 l: Liveness,
679696 inst: Air.Inst.Index,
......@@ -1108,23 +1125,15 @@ fn analyzeInst(
11081125 const inst_data = inst_datas[inst].pl_op;
11091126 const callee = inst_data.operand;
11101127 const extra = a.air.extraData(Air.Call, inst_data.payload);
1111 const args = @as([]const Air.Inst.Ref, @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]));
1112 if (args.len + 1 <= bpi - 1) {
1113 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
1114 buf[0] = callee;
1115 @memcpy(buf[1..][0..args.len], args);
1116 return analyzeOperands(a, pass, data, inst, buf);
1117 }
1118
1119 var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1);
1120 defer big.deinit();
1121 var i: usize = args.len;
1122 while (i > 0) {
1123 i -= 1;
1124 try big.feed(args[i]);
1125 }
1126 try big.feed(callee);
1127 return big.finish();
1128 const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]);
1129 return analyzeInstCall(a, pass, data, inst, callee, args);
1130 },
1131 .call_async => {
1132 const inst_data = inst_datas[inst].ty_pl;
1133 const extra = a.air.extraData(Air.AsyncCall, inst_data.payload);
1134 const callee = extra.data.callee;
1135 const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]);
1136 return analyzeInstCall(a, pass, data, inst, callee, args);
11281137 },
11291138 .select => {
11301139 const pl_op = inst_datas[inst].pl_op;
......@@ -1253,6 +1262,32 @@ fn analyzeInst(
12531262 }
12541263}
12551264
1265fn analyzeInstCall(
1266 a: *Analysis,
1267 comptime pass: LivenessPass,
1268 data: *LivenessPassData(pass),
1269 inst: Air.Inst.Index,
1270 callee: Air.Inst.Ref,
1271 args: []const Air.Inst.Ref,
1272) Allocator.Error!void {
1273 if (args.len + 1 <= bpi - 1) {
1274 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
1275 buf[0] = callee;
1276 @memcpy(buf[1..][0..args.len], args);
1277 return analyzeOperands(a, pass, data, inst, buf);
1278 }
1279
1280 var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1);
1281 defer big.deinit();
1282 var i: usize = args.len;
1283 while (i > 0) {
1284 i -= 1;
1285 try big.feed(args[i]);
1286 }
1287 try big.feed(callee);
1288 return big.finish();
1289}
1290
12561291/// Every instruction should hit this (after handling any nested bodies), in every pass. In the
12571292/// initial pass, it is responsible for marking deaths of the (first three) operands and noticing
12581293/// immediate deaths.
src/Liveness/Verify.zig+14
......@@ -349,6 +349,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
349349 }
350350 try self.verifyInst(inst);
351351 },
352 .call_async => {
353 const ty_pl = data[inst].ty_pl;
354 const extra = self.air.extraData(Air.AsyncCall, ty_pl.payload);
355 const args: []const Air.Inst.Ref = @ptrCast(
356 self.air.extra[extra.end..][0..extra.data.args_len],
357 );
358
359 var bt = self.liveness.iterateBigTomb(inst);
360 try self.verifyOperand(inst, extra.data.callee, bt.feed());
361 for (args) |arg| {
362 try self.verifyOperand(inst, arg, bt.feed());
363 }
364 try self.verifyInst(inst);
365 },
352366 .assembly => {
353367 const ty_pl = data[inst].ty_pl;
354368 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
src/Module.zig+58
......@@ -1437,6 +1437,7 @@ pub const Fn = struct {
14371437 generic_owner_decl: Decl.OptionalIndex,
14381438
14391439 state: Analysis,
1440 async_status: AsyncStatus,
14401441 is_cold: bool = false,
14411442 is_noinline: bool,
14421443 calls_or_awaits_errorable_fn: bool = false,
......@@ -1481,6 +1482,12 @@ pub const Fn = struct {
14811482 success,
14821483 };
14831484
1485 pub const AsyncStatus = enum {
1486 unknown,
1487 yes_async,
1488 not_async,
1489 };
1490
14841491 /// This struct is used to keep track of any dependencies related to functions instances
14851492 /// that return inferred error sets. Note that a function may be associated to
14861493 /// multiple different error sets, for example an inferred error set which
......@@ -1608,6 +1615,14 @@ pub const Fn = struct {
16081615 else => unreachable,
16091616 }
16101617 }
1618
1619 pub fn isAsync(func: Fn) bool {
1620 return switch (func.async_status) {
1621 .unknown => unreachable,
1622 .yes_async => true,
1623 .not_async => false,
1624 };
1625 }
16111626};
16121627
16131628pub const DeclAdapter = struct {
......@@ -2340,6 +2355,36 @@ pub const SrcLoc = struct {
23402355 const full = tree.fullCall(&buf, node).?;
23412356 return nodeToSpan(tree, full.ast.fn_expr);
23422357 },
2358 .node_offset_async_call_func => |node_off| {
2359 const tree = try src_loc.file_scope.getTree(gpa);
2360 const node_tags = tree.nodes.items(.tag);
2361 const node = src_loc.declRelativeToNodeIndex(node_off);
2362 const var_decl: Ast.full.VarDecl = switch (node_tags[node]) {
2363 .global_var_decl => tree.globalVarDecl(node),
2364 .local_var_decl => tree.localVarDecl(node),
2365 .simple_var_decl => tree.simpleVarDecl(node),
2366 .aligned_var_decl => tree.alignedVarDecl(node),
2367 else => unreachable,
2368 };
2369 const init_node = var_decl.ast.init_node;
2370 var params: [1]Ast.Node.Index = undefined;
2371 const full = switch (node_tags[init_node]) {
2372 .call_one,
2373 .call_one_comma,
2374 .async_call_one,
2375 .async_call_one_comma,
2376 => tree.callOne(&params, init_node),
2377
2378 .call,
2379 .call_comma,
2380 .async_call,
2381 .async_call_comma,
2382 => tree.callFull(init_node),
2383
2384 else => unreachable,
2385 };
2386 return nodeToSpan(tree, full.ast.fn_expr);
2387 },
23432388 .node_offset_field_name => |node_off| {
23442389 const tree = try src_loc.file_scope.getTree(gpa);
23452390 const node_datas = tree.nodes.items(.data);
......@@ -2963,6 +3008,14 @@ pub const LazySrcLoc = union(enum) {
29633008 /// to the callee expression.
29643009 /// The Decl is determined contextually.
29653010 node_offset_call_func: i32,
3011 /// Example:
3012 /// var a = async b();
3013 /// ~
3014 /// The source location points to the callee expression of a function call
3015 /// expression of a variable declaration, found by taking this AST node
3016 /// index offset from the containing Decl AST node, which points to the
3017 /// variable declaration node. The Decl is determined contextually.
3018 node_offset_async_call_func: i32,
29663019 /// The payload is offset from the containing Decl AST node.
29673020 /// The source location points to the field name of:
29683021 /// * a field access expression (`a.b`), or
......@@ -3192,6 +3245,7 @@ pub const LazySrcLoc = union(enum) {
31923245 .node_offset_slice_end,
31933246 .node_offset_slice_sentinel,
31943247 .node_offset_call_func,
3248 .node_offset_async_call_func,
31953249 .node_offset_field_name,
31963250 .node_offset_deref_ptr,
31973251 .node_offset_asm_source,
......@@ -6869,6 +6923,10 @@ pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) A
68696923 return (try mod.intern_pool.get(mod.gpa, .{ .error_set_type = .{ .names = names } })).toType();
68706924}
68716925
6926pub fn asyncFrameType(mod: *Module, func_index: Fn.Index) Allocator.Error!Type {
6927 return (try mod.intern_pool.get(mod.gpa, .{ .async_frame_type = func_index })).toType();
6928}
6929
68726930/// Sorts `names` in place.
68736931pub fn errorSetFromUnsortedNames(
68746932 mod: *Module,
src/Sema.zig+141-46
......@@ -941,8 +941,9 @@ fn analyzeBodyInner(
941941 .bool_br_and => try sema.zirBoolBr(block, inst, false),
942942 .bool_br_or => try sema.zirBoolBr(block, inst, true),
943943 .c_import => try sema.zirCImport(block, inst),
944 .call => try sema.zirCall(block, inst, .direct),
945 .field_call => try sema.zirCall(block, inst, .field),
944 .call => try sema.zirCall(block, inst, Zir.Inst.Call),
945 .field_call => try sema.zirCall(block, inst, Zir.Inst.FieldCall),
946 .async_call => try sema.zirAsyncCall(block, inst),
946947 .closure_get => try sema.zirClosureGet(block, inst),
947948 .cmp_lt => try sema.zirCmp(block, inst, .lt),
948949 .cmp_lte => try sema.zirCmp(block, inst, .lte),
......@@ -6435,7 +6436,7 @@ fn zirCall(
64356436 sema: *Sema,
64366437 block: *Block,
64376438 inst: Zir.Inst.Index,
6438 comptime kind: enum { direct, field },
6439 comptime ExtraType: type,
64396440) CompileError!Air.Inst.Ref {
64406441 const tracy = trace(@src());
64416442 defer tracy.end();
......@@ -6444,10 +6445,6 @@ fn zirCall(
64446445 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
64456446 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
64466447 const call_src = inst_data.src();
6447 const ExtraType = switch (kind) {
6448 .direct => Zir.Inst.Call,
6449 .field => Zir.Inst.FieldCall,
6450 };
64516448 const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
64526449 const args_len = extra.data.flags.args_len;
64536450
......@@ -6455,38 +6452,90 @@ fn zirCall(
64556452 const ensure_result_used = extra.data.flags.ensure_result_used;
64566453 const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
64576454
6458 const callee: ResolvedFieldCallee = switch (kind) {
6459 .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
6460 .field => blk: {
6455 const callee: ResolvedFieldCallee = switch (ExtraType) {
6456 Zir.Inst.Call => .{ .direct = try sema.resolveInst(extra.data.callee) },
6457 Zir.Inst.FieldCall => blk: {
64616458 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
64626459 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));
64636460 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
64646461 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
64656462 },
6463 else => @compileError("unreachable"),
64666464 };
6465 return callCommon(
6466 sema,
6467 block,
6468 inst,
6469 callee_src,
6470 call_src,
6471 callee,
6472 args_len,
6473 modifier,
6474 extra.end,
6475 ensure_result_used,
6476 pop_error_return_trace,
6477 );
6478}
6479
6480fn zirAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6481 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6482 const func_src: LazySrcLoc = .{ .node_offset_async_call_func = inst_data.src_node };
6483 const call_src: LazySrcLoc = .{ .node_offset_var_decl_init = inst_data.src_node };
6484 const extra = sema.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index);
6485 const args_len = extra.data.args_len;
6486 const callee: ResolvedFieldCallee = .{ .direct = try sema.resolveInst(extra.data.callee) };
6487 return callCommon(
6488 sema,
6489 block,
6490 inst,
6491 func_src,
6492 call_src,
6493 callee,
6494 args_len,
6495 .async_kw,
6496 extra.end,
6497 false,
6498 false,
6499 );
6500}
6501
6502fn callCommon(
6503 sema: *Sema,
6504 block: *Block,
6505 inst: Zir.Inst.Index,
6506 callee_src: LazySrcLoc,
6507 call_src: LazySrcLoc,
6508 callee: ResolvedFieldCallee,
6509 args_len: u32,
6510 modifier: std.builtin.CallModifier,
6511 extra_end: usize,
6512 ensure_result_used: bool,
6513 pop_error_return_trace: bool,
6514) CompileError!Air.Inst.Ref {
6515 const mod = sema.mod;
6516
64676517 var resolved_args: []Air.Inst.Ref = undefined;
64686518 var bound_arg_src: ?LazySrcLoc = null;
6469 var func: Air.Inst.Ref = undefined;
64706519 var arg_index: u32 = 0;
6471 switch (callee) {
6472 .direct => |func_inst| {
6520 const func: Air.Inst.Ref = switch (callee) {
6521 .direct => |func_inst| f: {
64736522 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6474 func = func_inst;
6523 break :f func_inst;
64756524 },
6476 .method => |method| {
6525 .method => |method| f: {
64776526 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6478 func = method.func_inst;
64796527 resolved_args[0] = method.arg0_inst;
64806528 arg_index += 1;
64816529 bound_arg_src = callee_src;
6530 break :f method.func_inst;
64826531 },
6483 }
6532 };
64846533
64856534 const callee_ty = sema.typeOf(func);
64866535 const total_args = args_len + @intFromBool(bound_arg_src != null);
64876536 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
64886537
6489 const args_body = sema.code.extra[extra.end..];
6538 const args_body = sema.code.extra[extra_end..];
64906539
64916540 var input_is_error = false;
64926541 const block_index = @as(Air.Inst.Index, @intCast(block.instructions.items.len));
......@@ -6501,7 +6550,7 @@ fn zirCall(
65016550 arg_index += 1;
65026551 }) {
65036552 const func_ty_info = mod.typeToFunc(func_ty).?;
6504 const arg_end = sema.code.extra[extra.end + extra_index];
6553 const arg_end = sema.code.extra[extra_end + extra_index];
65056554 defer arg_start = arg_end;
65066555
65076556 // Generate args to comptime params in comptime block.
......@@ -6730,8 +6779,7 @@ fn analyzeCall(
67306779 .never_tail => Air.Inst.Tag.call_never_tail,
67316780 .never_inline => Air.Inst.Tag.call_never_inline,
67326781 .always_tail => Air.Inst.Tag.call_always_tail,
6733
6734 .async_kw => return sema.failWithUseOfAsync(block, call_src),
6782 .async_kw => Air.Inst.Tag.call_async,
67356783 };
67366784
67376785 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
......@@ -7158,18 +7206,20 @@ fn analyzeCall(
71587206 }
71597207 }
71607208
7161 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
7162 args.len);
7163 const func_inst = try block.addInst(.{
7164 .tag = call_tag,
7165 .data = .{ .pl_op = .{
7166 .operand = func,
7167 .payload = sema.addExtraAssumeCapacity(Air.Call{
7168 .args_len = @as(u32, @intCast(args.len)),
7169 }),
7170 } },
7171 });
7172 sema.appendRefsAssumeCapacity(args);
7209 if (call_tag == .call_async) {
7210 const func_val = sema.resolveConstValue(block, func_src, func, "function is not comptime-known; @asyncCall required") catch |err| {
7211 if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err);
7212 return err;
7213 };
7214 const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
7215 .func => |function| function.index,
7216 .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?,
7217 else => unreachable,
7218 };
7219 break :res try addAsyncCallInst(sema, block, func, module_fn_index, args);
7220 }
7221
7222 const func_inst = try addCallInst(sema, block, func, args, call_tag);
71737223
71747224 if (call_tag == .call_always_tail) {
71757225 if (ensure_result_used) {
......@@ -7206,6 +7256,56 @@ fn analyzeCall(
72067256 return result;
72077257}
72087258
7259fn addCallInst(
7260 sema: *Sema,
7261 block: *Block,
7262 callee: Air.Inst.Ref,
7263 args: []const Air.Inst.Ref,
7264 call_tag: Air.Inst.Tag,
7265) Allocator.Error!Air.Inst.Ref {
7266 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
7267 args.len);
7268 const call_inst = try block.addInst(.{
7269 .tag = call_tag,
7270 .data = .{ .pl_op = .{
7271 .operand = callee,
7272 .payload = sema.addExtraAssumeCapacity(Air.Call{
7273 .args_len = @intCast(args.len),
7274 }),
7275 } },
7276 });
7277 sema.appendRefsAssumeCapacity(args);
7278 return call_inst;
7279}
7280
7281fn addAsyncCallInst(
7282 sema: *Sema,
7283 block: *Block,
7284 callee: Air.Inst.Ref,
7285 callee_fn: Module.Fn.Index,
7286 args: []const Air.Inst.Ref,
7287) Allocator.Error!Air.Inst.Ref {
7288 const mod = sema.mod;
7289 const frame_ty = try mod.asyncFrameType(callee_fn);
7290 const frame_ty_ref = try sema.addType(frame_ty);
7291 try sema.air_extra.ensureUnusedCapacity(
7292 sema.gpa,
7293 @typeInfo(Air.AsyncCall).Struct.fields.len + args.len,
7294 );
7295 const call_inst = try block.addInst(.{
7296 .tag = .call_async,
7297 .data = .{ .ty_pl = .{
7298 .ty = frame_ty_ref,
7299 .payload = sema.addExtraAssumeCapacity(Air.AsyncCall{
7300 .callee = callee,
7301 .args_len = @intCast(args.len),
7302 }),
7303 } },
7304 });
7305 sema.appendRefsAssumeCapacity(args);
7306 return call_inst;
7307}
7308
72097309fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
72107310 const mod = sema.mod;
72117311 const target = mod.getTarget();
......@@ -7664,19 +7764,10 @@ fn instantiateGenericCall(
76647764 }
76657765
76667766 try mod.ensureFuncBodyAnalysisQueued(callee_index);
7667
7668 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
7669 runtime_args_len);
7670 const result = try block.addInst(.{
7671 .tag = call_tag,
7672 .data = .{ .pl_op = .{
7673 .operand = callee_inst,
7674 .payload = sema.addExtraAssumeCapacity(Air.Call{
7675 .args_len = runtime_args_len,
7676 }),
7677 } },
7678 });
7679 sema.appendRefsAssumeCapacity(runtime_args);
7767 const result = switch (call_tag) {
7768 .call_async => try addAsyncCallInst(sema, block, callee_inst, callee_index, runtime_args),
7769 else => try addCallInst(sema, block, callee_inst, runtime_args, call_tag),
7770 };
76807771
76817772 if (ensure_result_used) {
76827773 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
......@@ -9221,6 +9312,7 @@ fn funcCommon(
92219312 const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
92229313 new_func.* = .{
92239314 .state = anal_state,
9315 .async_status = .unknown,
92249316 .zir_body_inst = func_inst,
92259317 .owner_decl = sema.owner_decl_index,
92269318 .generic_owner_decl = generic_owner_decl,
......@@ -33730,6 +33822,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3373033822 .error_set_type, .inferred_error_set_type => false,
3373133823
3373233824 .func_type => true,
33825 .async_frame_type => false,
3373333826
3373433827 .simple_type => |t| switch (t) {
3373533828 .f16,
......@@ -35271,6 +35364,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3527135364 .type_inferred_error_set,
3527235365 .type_opaque,
3527335366 .type_function,
35367 .type_async_frame,
3527435368 => null,
3527535369 .simple_type, // handled above
3527635370 // values, not types
......@@ -35934,6 +36028,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3593436028 },
3593536029
3593636030 .opaque_type => false,
36031 .async_frame_type => false,
3593736032 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
3593836033
3593936034 // values, not types
src/TypedValue.zig+1
......@@ -192,6 +192,7 @@ pub fn print(
192192 .func_type,
193193 .error_set_type,
194194 .inferred_error_set_type,
195 .async_frame_type,
195196 => return Type.print(val.toType(), writer, mod),
196197 .undef => return writer.writeAll("undefined"),
197198 .runtime_value => return writer.writeAll("(runtime value)"),
src/Zir.zig+21-2
......@@ -313,6 +313,11 @@ pub const Inst = struct {
313313 /// Uses the `pl_node` union field with payload `BuiltinCall`.
314314 /// AST node is the builtin call.
315315 builtin_call,
316 /// An async function call that also acts as an alloc. Corresponds with
317 /// the syntax `var foo = async bar();`.
318 /// Uses the `pl_node` union field with payload `AsyncCall`
319 /// AST node is the entire variable declaration, with the init node being a call.
320 async_call,
316321 /// `<`
317322 /// Uses the `pl_node` union field. Payload is `Bin`.
318323 cmp_lt,
......@@ -1026,6 +1031,7 @@ pub const Inst = struct {
10261031 .bool_not,
10271032 .call,
10281033 .field_call,
1034 .async_call,
10291035 .cmp_lt,
10301036 .cmp_lte,
10311037 .cmp_eq,
......@@ -1330,6 +1336,7 @@ pub const Inst = struct {
13301336 .bool_not,
13311337 .call,
13321338 .field_call,
1339 .async_call,
13331340 .cmp_lt,
13341341 .cmp_lte,
13351342 .cmp_eq,
......@@ -1564,6 +1571,7 @@ pub const Inst = struct {
15641571 .for_len = .pl_node,
15651572 .call = .pl_node,
15661573 .field_call = .pl_node,
1574 .async_call = .pl_node,
15671575 .cmp_lt = .pl_node,
15681576 .cmp_lte = .pl_node,
15691577 .cmp_eq = .pl_node,
......@@ -1944,7 +1952,7 @@ pub const Inst = struct {
19441952 /// `small` contains `NameStrategy`.
19451953 reify,
19461954 /// Implements the `@asyncCall` builtin.
1947 /// `operand` is payload index to `AsyncCall`.
1955 /// `operand` is payload index to `BuiltinAsyncCall`.
19481956 builtin_async_call,
19491957 /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins.
19501958 /// `small` 0=>weak 1=>strong
......@@ -2531,6 +2539,16 @@ pub const Inst = struct {
25312539 field_name_start: u32,
25322540 };
25332541
2542 /// Not to be confused with BuiltinAsyncCall.
2543 /// Stored inside extra, with trailing arguments according to `args_len`.
2544 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
2545 /// 1. arg_end: u32, // for each `args_len`
2546 /// arg_N_start is the same as arg_N-1_end
2547 pub const AsyncCall = struct {
2548 callee: Ref,
2549 args_len: u32,
2550 };
2551
25342552 pub const TypeOfPeer = struct {
25352553 src_node: i32,
25362554 body_len: u32,
......@@ -3101,7 +3119,8 @@ pub const Inst = struct {
31013119 b: Ref,
31023120 };
31033121
3104 pub const AsyncCall = struct {
3122 /// Not to be confused with AsyncCall.
3123 pub const BuiltinAsyncCall = struct {
31053124 node: i32,
31063125 frame_buffer: Ref,
31073126 result_ptr: Ref,
src/arch/aarch64/CodeGen.zig+2
......@@ -819,6 +819,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
819819 .call_always_tail => try self.airCall(inst, .always_tail),
820820 .call_never_tail => try self.airCall(inst, .never_tail),
821821 .call_never_inline => try self.airCall(inst, .never_inline),
822 .call_async => try self.airCall(inst, .async_kw),
822823
823824 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
824825 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -4242,6 +4243,7 @@ fn airFence(self: *Self) !void {
42424243
42434244fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
42444245 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});
4246 if (modifier == .async_kw) return self.fail("TODO implement async calls for aarch64", .{});
42454247 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
42464248 const callee = pl_op.operand;
42474249 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/arch/arm/CodeGen.zig+2
......@@ -803,6 +803,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
803803 .call_always_tail => try self.airCall(inst, .always_tail),
804804 .call_never_tail => try self.airCall(inst, .never_tail),
805805 .call_never_inline => try self.airCall(inst, .never_inline),
806 .call_async => try self.airCall(inst, .async_kw),
806807
807808 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
808809 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -4215,6 +4216,7 @@ fn airFence(self: *Self) !void {
42154216
42164217fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
42174218 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});
4219 if (modifier == .async_kw) return self.fail("TODO implement async calls for arm", .{});
42184220 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
42194221 const callee = pl_op.operand;
42204222 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/arch/riscv64/CodeGen.zig+2
......@@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
638638 .call_always_tail => try self.airCall(inst, .always_tail),
639639 .call_never_tail => try self.airCall(inst, .never_tail),
640640 .call_never_inline => try self.airCall(inst, .never_inline),
641 .call_async => try self.airCall(inst, .async_kw),
641642
642643 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
643644 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -1707,6 +1708,7 @@ fn airFence(self: *Self) !void {
17071708fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
17081709 const mod = self.bin_file.options.module.?;
17091710 if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{});
1711 if (modifier == .async_kw) return self.fail("TODO implement async calls for riscv64", .{});
17101712 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
17111713 const fn_ty = self.typeOf(pl_op.operand);
17121714 const callee = pl_op.operand;
src/arch/sparc64/CodeGen.zig+2
......@@ -651,6 +651,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
651651 .call_always_tail => try self.airCall(inst, .always_tail),
652652 .call_never_tail => try self.airCall(inst, .never_tail),
653653 .call_never_inline => try self.airCall(inst, .never_inline),
654 .call_async => try self.airCall(inst, .async_kw),
654655
655656 .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"),
656657 .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"),
......@@ -1293,6 +1294,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
12931294
12941295fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
12951296 if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});
1297 if (modifier == .async_kw) return self.fail("TODO implement async calls for {}", .{self.target.cpu.arch});
12961298
12971299 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
12981300 const callee = pl_op.operand;
src/arch/wasm/CodeGen.zig+3
......@@ -1930,6 +1930,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19301930 .call_always_tail => func.airCall(inst, .always_tail),
19311931 .call_never_tail => func.airCall(inst, .never_tail),
19321932 .call_never_inline => func.airCall(inst, .never_inline),
1933 .call_async => func.airCall(inst, .async_kw),
19331934
19341935 .is_err => func.airIsErr(inst, .i32_ne),
19351936 .is_non_err => func.airIsErr(inst, .i32_eq),
......@@ -2180,6 +2181,7 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21802181
21812182fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
21822183 if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{});
2184 if (modifier == .async_kw) return func.fail("TODO implement async calls for wasm", .{});
21832185 const pl_op = func.air.instructions.items(.data)[inst].pl_op;
21842186 const extra = func.air.extraData(Air.Call, pl_op.payload);
21852187 const args = @as([]const Air.Inst.Ref, @ptrCast(func.air.extra[extra.end..][0..extra.data.args_len]));
......@@ -3125,6 +3127,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
31253127 .func_type,
31263128 .error_set_type,
31273129 .inferred_error_set_type,
3130 .async_frame_type,
31283131 => unreachable, // types, not values
31293132
31303133 .undef, .runtime_value => unreachable, // handled above
src/arch/x86_64/CodeGen.zig+2
......@@ -1901,6 +1901,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
19011901 .call_always_tail => try self.airCall(inst, .always_tail),
19021902 .call_never_tail => try self.airCall(inst, .never_tail),
19031903 .call_never_inline => try self.airCall(inst, .never_inline),
1904 .call_async => try self.airCall(inst, .async_kw),
19041905
19051906 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
19061907 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
......@@ -8059,6 +8060,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
80598060fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
80608061 const mod = self.bin_file.options.module.?;
80618062 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
8063 if (modifier == .async_kw) return self.fail("TODO implement async calls for x86_64", .{});
80628064 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
80638065 const callee = pl_op.operand;
80648066 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/codegen.zig+1
......@@ -222,6 +222,7 @@ pub fn generateSymbol(
222222 .func_type,
223223 .error_set_type,
224224 .inferred_error_set_type,
225 .async_frame_type,
225226 => unreachable, // types, not values
226227
227228 .undef, .runtime_value => unreachable, // handled above
src/codegen/c.zig+2
......@@ -927,6 +927,7 @@ pub const DeclGen = struct {
927927 .func_type,
928928 .error_set_type,
929929 .inferred_error_set_type,
930 .async_frame_type,
930931 // memoization, not values
931932 .memoized_call,
932933 => unreachable,
......@@ -2999,6 +3000,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29993000 .call_always_tail => .none,
30003001 .call_never_tail => try airCall(f, inst, .never_tail),
30013002 .call_never_inline => try airCall(f, inst, .never_inline),
3003 .call_async => try airCall(f, inst, .async_kw),
30023004
30033005 .float_from_int,
30043006 .int_from_float,
src/codegen/llvm.zig+56-2
......@@ -3017,11 +3017,58 @@ pub const Object = struct {
30173017 .Null => unreachable,
30183018 .EnumLiteral => unreachable,
30193019
3020 .Frame => @panic("TODO implement llvmType for Frame types"),
3021 .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),
3020 .Frame => {
3021 const gop = try o.type_map.getOrPut(gpa, t.toIntern());
3022 if (gop.found_existing) return gop.value_ptr.*;
3023
3024 const func_index = mod.intern_pool.indexToKey(t.toIntern()).async_frame_type;
3025 const func = mod.funcPtr(func_index);
3026 const owner_decl = mod.declPtr(func.owner_decl);
3027
3028 var name_buf = std.ArrayList(u8).init(gpa);
3029 defer name_buf.deinit();
3030 try name_buf.appendSlice("@Frame(");
3031 try owner_decl.renderFullyQualifiedName(mod, name_buf.writer());
3032 try name_buf.appendSlice(")\x00");
3033 const name = name_buf.items[0 .. name_buf.items.len - 1 :0];
3034
3035 const llvm_struct_ty = o.context.structCreateNamed(name);
3036 gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
3037
3038 return lowerAsyncFrameType(o, func, llvm_struct_ty);
3039 //if (func.isAsync()) {
3040 // return lowerAsyncFrameType(o, func, llvm_struct_ty);
3041 //} else {
3042 // @panic("lower llvm @Frame() type of non-async function");
3043 //}
3044 },
3045 .AnyFrame => return o.context.pointerType(0),
30223046 }
30233047 }
30243048
3049 fn lowerAsyncFrameType(
3050 o: *Object,
3051 func: *Module.Fn,
3052 llvm_struct_ty: *llvm.Type,
3053 ) Allocator.Error!*llvm.Type {
3054 const gpa = o.gpa;
3055 var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{};
3056 defer llvm_field_types.deinit(gpa);
3057
3058 try llvm_field_types.ensureUnusedCapacity(gpa, 1);
3059 _ = func;
3060 llvm_field_types.appendAssumeCapacity(o.context.intType(32));
3061
3062 const any_underaligned_fields = false;
3063 llvm_struct_ty.structSetBody(
3064 llvm_field_types.items.ptr,
3065 @intCast(llvm_field_types.items.len),
3066 llvm.Bool.fromBool(any_underaligned_fields),
3067 );
3068
3069 return llvm_struct_ty;
3070 }
3071
30253072 fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {
30263073 const mod = o.module;
30273074 const fn_info = mod.typeToFunc(fn_ty).?;
......@@ -3148,6 +3195,7 @@ pub const Object = struct {
31483195 .func_type,
31493196 .error_set_type,
31503197 .inferred_error_set_type,
3198 .async_frame_type,
31513199 => unreachable, // types, not values
31523200
31533201 .undef, .runtime_value => unreachable, // handled above
......@@ -4474,6 +4522,7 @@ pub const FuncGen = struct {
44744522 .call_always_tail => try self.airCall(inst, .AlwaysTail),
44754523 .call_never_tail => try self.airCall(inst, .NeverTail),
44764524 .call_never_inline => try self.airCall(inst, .NeverInline),
4525 .call_async => try self.airCallAsync(inst),
44774526
44784527 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
44794528 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
......@@ -4939,6 +4988,11 @@ pub const FuncGen = struct {
49394988 _ = fg.builder.buildUnreachable();
49404989 }
49414990
4991 fn airCallAsync(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
4992 _ = inst;
4993 return self.todo("lower async call", .{});
4994 }
4995
49424996 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
49434997 const o = self.dg.object;
49444998 const mod = o.module;
src/codegen/spirv.zig+1
......@@ -642,6 +642,7 @@ pub const DeclGen = struct {
642642 .func_type,
643643 .error_set_type,
644644 .inferred_error_set_type,
645 .async_frame_type,
645646 => unreachable, // types, not values
646647
647648 .undef, .runtime_value => unreachable, // handled above
src/print_air.zig+21-2
......@@ -329,6 +329,7 @@ const Writer = struct {
329329 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
330330 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
331331 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
332 .call_async => try w.writeCallAsync(s, inst),
332333
333334 .dbg_block_begin, .dbg_block_end => {},
334335
......@@ -699,8 +700,26 @@ const Writer = struct {
699700 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
700701 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
701702 const extra = w.air.extraData(Air.Call, pl_op.payload);
702 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]));
703 try w.writeOperand(s, inst, 0, pl_op.operand);
703 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);
704 return finishWriteCall(w, s, inst, pl_op.operand, args);
705 }
706
707 fn writeCallAsync(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
708 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
709 const extra = w.air.extraData(Air.AsyncCall, ty_pl.payload);
710 const callee = extra.data.callee;
711 const args: []const Air.Inst.Ref = @ptrCast(w.air.extra[extra.end..][0..extra.data.args_len]);
712 return finishWriteCall(w, s, inst, callee, args);
713 }
714
715 fn finishWriteCall(
716 w: *Writer,
717 s: anytype,
718 inst: Air.Inst.Index,
719 callee: Air.Inst.Ref,
720 args: []const Air.Inst.Ref,
721 ) @TypeOf(s).Error!void {
722 try w.writeOperand(s, inst, 0, callee);
704723 try s.writeAll(", [");
705724 for (args, 0..) |arg, i| {
706725 if (i != 0) try s.writeAll(", ");
src/print_zir.zig+31-5
......@@ -362,6 +362,7 @@ const Writer = struct {
362362
363363 .call => try self.writeCall(stream, inst, .direct),
364364 .field_call => try self.writeCall(stream, inst, .field),
365 .async_call => try self.writeAsyncCall(stream, inst),
365366
366367 .block,
367368 .block_comptime,
......@@ -837,7 +838,7 @@ const Writer = struct {
837838 }
838839
839840 fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
840 const extra = self.code.extraData(Zir.Inst.AsyncCall, extended.operand).data;
841 const extra = self.code.extraData(Zir.Inst.BuiltinAsyncCall, extended.operand).data;
841842 try self.writeInstRef(stream, extra.frame_buffer);
842843 try stream.writeAll(", ");
843844 try self.writeInstRef(stream, extra.result_ptr);
......@@ -1187,11 +1188,13 @@ const Writer = struct {
11871188 try self.writeSrc(stream, src);
11881189 }
11891190
1191 const CallKind = enum { direct, field };
1192
11901193 fn writeCall(
11911194 self: *Writer,
11921195 stream: anytype,
11931196 inst: Zir.Inst.Index,
1194 comptime kind: enum { direct, field },
1197 comptime kind: CallKind,
11951198 ) !void {
11961199 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
11971200 const ExtraType = switch (kind) {
......@@ -1201,11 +1204,12 @@ const Writer = struct {
12011204 const extra = self.code.extraData(ExtraType, inst_data.payload_index);
12021205 const args_len = extra.data.flags.args_len;
12031206 const body = self.code.extra[extra.end..];
1207 const modifier: std.builtin.CallModifier = @enumFromInt(extra.data.flags.packed_modifier);
12041208
12051209 if (extra.data.flags.ensure_result_used) {
12061210 try stream.writeAll("nodiscard ");
12071211 }
1208 try stream.print(".{s}, ", .{@tagName(@as(std.builtin.CallModifier, @enumFromInt(extra.data.flags.packed_modifier)))});
1212 try stream.print(".{s}, ", .{@tagName(modifier)});
12091213 switch (kind) {
12101214 .direct => try self.writeInstRef(stream, extra.data.callee),
12111215 .field => {
......@@ -1214,6 +1218,28 @@ const Writer = struct {
12141218 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});
12151219 },
12161220 }
1221 return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src());
1222 }
1223
1224 fn writeAsyncCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1225 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1226 const extra = self.code.extraData(Zir.Inst.AsyncCall, inst_data.payload_index);
1227 const args_len = extra.data.args_len;
1228 const body = self.code.extra[extra.end..];
1229 const callee = extra.data.callee;
1230 try stream.print(".{s}, ", .{@tagName(std.builtin.CallModifier.async_kw)});
1231 try self.writeInstRef(stream, callee);
1232 return finishWriteCall(self, stream, body, args_len, extra.end, inst_data.src());
1233 }
1234
1235 fn finishWriteCall(
1236 self: *Writer,
1237 stream: anytype,
1238 body: []const Zir.Inst.Index,
1239 args_len: u32,
1240 extra_end: usize,
1241 src: Module.LazySrcLoc,
1242 ) !void {
12171243 try stream.writeAll(", [");
12181244
12191245 self.indent += 2;
......@@ -1224,7 +1250,7 @@ const Writer = struct {
12241250 var arg_start: u32 = args_len;
12251251 while (i < args_len) : (i += 1) {
12261252 try stream.writeByteNTimes(' ', self.indent);
1227 const arg_end = self.code.extra[extra.end + i];
1253 const arg_end = self.code.extra[extra_end + i];
12281254 defer arg_start = arg_end;
12291255 const arg_body = body[arg_start..arg_end];
12301256 try self.writeBracedBody(stream, arg_body);
......@@ -1237,7 +1263,7 @@ const Writer = struct {
12371263 }
12381264
12391265 try stream.writeAll("]) ");
1240 try self.writeSrc(stream, inst_data.src());
1266 try self.writeSrc(stream, src);
12411267 }
12421268
12431269 fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
src/type.zig+38-1
......@@ -409,6 +409,13 @@ pub const Type = struct {
409409 try writer.writeAll("anyframe->");
410410 return print(child.toType(), writer, mod);
411411 },
412 .async_frame_type => |func_index| {
413 const func = mod.funcPtr(func_index);
414 const owner_decl = mod.declPtr(func.owner_decl);
415 try writer.writeAll("@Frame(");
416 try owner_decl.renderFullyQualifiedName(mod, writer);
417 try writer.writeAll(")");
418 },
412419
413420 // values, not types
414421 .undef,
......@@ -506,6 +513,7 @@ pub const Type = struct {
506513 .error_union_type,
507514 .error_set_type,
508515 .inferred_error_set_type,
516 .async_frame_type,
509517 => true,
510518
511519 // These are function *bodies*, not pointers.
......@@ -666,6 +674,7 @@ pub const Type = struct {
666674 .anon_struct_type,
667675 .opaque_type,
668676 .anyframe_type,
677 .async_frame_type,
669678 // These are function bodies, not function pointers.
670679 .func_type,
671680 => false,
......@@ -1068,6 +1077,9 @@ pub const Type = struct {
10681077 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
10691078 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
10701079
1080 // TODO: revisit this
1081 .async_frame_type => return AbiAlignmentAdvanced{ .scalar = 16 },
1082
10711083 // values, not types
10721084 .undef,
10731085 .runtime_value,
......@@ -1484,6 +1496,25 @@ pub const Type = struct {
14841496 .opaque_type => unreachable, // no size available
14851497 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },
14861498
1499 .async_frame_type => {
1500 switch (strat) {
1501 .sema => |sema| {
1502 _ = sema;
1503 @panic("they asked for the size of an async frame from sema");
1504 },
1505 .lazy => {
1506 // TODO: sometimes this might already be resolved
1507 return .{ .val = (try mod.intern(.{ .int = .{
1508 .ty = .comptime_int_type,
1509 .storage = .{ .lazy_size = ty.toIntern() },
1510 } })).toValue() };
1511 },
1512 .eager => {
1513 @panic("they eagerly asked for the size of an async frame");
1514 },
1515 }
1516 },
1517
14871518 // values, not types
14881519 .undef,
14891520 .runtime_value,
......@@ -1509,7 +1540,7 @@ pub const Type = struct {
15091540 }
15101541 }
15111542
1512 pub fn abiSizeAdvancedUnion(
1543 fn abiSizeAdvancedUnion(
15131544 ty: Type,
15141545 mod: *Module,
15151546 strat: AbiAlignmentAdvancedStrat,
......@@ -1717,6 +1748,9 @@ pub const Type = struct {
17171748 },
17181749 .opaque_type => unreachable,
17191750 .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema),
1751 .async_frame_type => {
1752 @panic("TODO bitSize async_frame_type");
1753 },
17201754
17211755 // values, not types
17221756 .undef,
......@@ -2263,6 +2297,7 @@ pub const Type = struct {
22632297
22642298 .ptr_type => unreachable,
22652299 .anyframe_type => unreachable,
2300 .async_frame_type => unreachable,
22662301 .array_type => unreachable,
22672302
22682303 .opt_type => unreachable,
......@@ -2445,6 +2480,7 @@ pub const Type = struct {
24452480 .anyframe_type,
24462481 .error_set_type,
24472482 .inferred_error_set_type,
2483 .async_frame_type,
24482484 => return null,
24492485
24502486 inline .array_type, .vector_type => |seq_type, seq_tag| {
......@@ -2760,6 +2796,7 @@ pub const Type = struct {
27602796 },
27612797
27622798 .opaque_type => false,
2799 .async_frame_type => false,
27632800
27642801 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
27652802
src/value.zig+1
......@@ -349,6 +349,7 @@ pub const Value = struct {
349349 .func_type,
350350 .error_set_type,
351351 .inferred_error_set_type,
352 .async_frame_type,
352353
353354 .undef,
354355 .runtime_value,