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 {...@@ -310,6 +310,9 @@ pub const Inst = struct {
310 call_never_tail,310 call_never_tail,
311 /// Same as `call` except with the `never_inline` attribute.311 /// Same as `call` except with the `never_inline` attribute.
312 call_never_inline,312 call_never_inline,
313 /// Async function call.
314 /// Uses `ty_pl` field with the `AsyncCall` payload.
315 call_async,
313 /// Count leading zeroes of an integer according to its representation in twos complement.316 /// Count leading zeroes of an integer according to its representation in twos complement.
314 /// Result type will always be an unsigned integer big enough to fit the answer.317 /// Result type will always be an unsigned integer big enough to fit the answer.
315 /// Uses the `ty_op` field.318 /// Uses the `ty_op` field.
...@@ -1070,6 +1073,12 @@ pub const Call = struct {...@@ -1070,6 +1073,12 @@ pub const Call = struct {
1070 args_len: u32,1073 args_len: u32,
1071};1074};
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
1073/// This data is stored inside extra, with two sets of trailing `Inst.Ref`:1082/// This data is stored inside extra, with two sets of trailing `Inst.Ref`:
1074/// * 0. the then body, according to `then_body_len`.1083/// * 0. the then body, according to `then_body_len`.
1075/// * 1. the else body, according to `else_body_len`.1084/// * 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)...@@ -1340,6 +1349,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1340 .ptr_add,1349 .ptr_add,
1341 .ptr_sub,1350 .ptr_sub,
1342 .try_ptr,1351 .try_ptr,
1352 .call_async,
1343 => return air.getRefType(datas[inst].ty_pl.ty),1353 => return air.getRefType(datas[inst].ty_pl.ty),
13441354
1345 .interned => return ip.typeOf(datas[inst].interned).toType(),1355 .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 {...@@ -1583,6 +1593,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1583 .call_always_tail,1593 .call_always_tail,
1584 .call_never_tail,1594 .call_never_tail,
1585 .call_never_inline,1595 .call_never_inline,
1596 .call_async,
1586 .cond_br,1597 .cond_br,
1587 .switch_br,1598 .switch_br,
1588 .@"try",1599 .@"try",
src/AstGen.zig+2-1
...@@ -2788,6 +2788,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2788,6 +2788,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2788 .validate_deref,2788 .validate_deref,
2789 .save_err_ret_index,2789 .save_err_ret_index,
2790 .restore_err_ret_index,2790 .restore_err_ret_index,
2791 .async_call,
2791 => break :b true,2792 => break :b true,
27922793
2793 .@"defer" => unreachable,2794 .@"defer" => unreachable,
...@@ -8701,7 +8702,7 @@ fn builtinCall(...@@ -8701,7 +8702,7 @@ fn builtinCall(
8701 return rvalue(gz, ri, result, node);8702 return rvalue(gz, ri, result, node);
8702 },8703 },
8703 .async_call => {8704 .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{
8705 .node = gz.nodeIndexToRelative(node),8706 .node = gz.nodeIndexToRelative(node),
8706 .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]),8707 .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]),
8707 .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),8708 .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
src/InternPool.zig+24
...@@ -209,6 +209,8 @@ pub const Key = union(enum) {...@@ -209,6 +209,8 @@ pub const Key = union(enum) {
209 /// `anyframe->T`. The payload is the child type, which may be `none` to indicate209 /// `anyframe->T`. The payload is the child type, which may be `none` to indicate
210 /// `anyframe`.210 /// `anyframe`.
211 anyframe_type: Index,211 anyframe_type: Index,
212 /// The payload is the function whose frame it refers to.
213 async_frame_type: Module.Fn.Index,
212 error_union_type: ErrorUnionType,214 error_union_type: ErrorUnionType,
213 simple_type: SimpleType,215 simple_type: SimpleType,
214 /// This represents a struct that has been explicitly declared in source code,216 /// This represents a struct that has been explicitly declared in source code,
...@@ -711,6 +713,7 @@ pub const Key = union(enum) {...@@ -711,6 +713,7 @@ pub const Key = union(enum) {
711 .enum_tag,713 .enum_tag,
712 .empty_enum_value,714 .empty_enum_value,
713 .inferred_error_set_type,715 .inferred_error_set_type,
716 .async_frame_type,
714 .un,717 .un,
715 => |x| Hash.hash(seed, asBytes(&x)),718 => |x| Hash.hash(seed, asBytes(&x)),
716719
...@@ -930,6 +933,10 @@ pub const Key = union(enum) {...@@ -930,6 +933,10 @@ pub const Key = union(enum) {
930 const b_info = b.error_union_type;933 const b_info = b.error_union_type;
931 return std.meta.eql(a_info, b_info);934 return std.meta.eql(a_info, b_info);
932 },935 },
936 .async_frame_type => |a_info| {
937 const b_info = b.async_frame_type;
938 return a_info == b_info;
939 },
933 .simple_type => |a_info| {940 .simple_type => |a_info| {
934 const b_info = b.simple_type;941 const b_info = b.simple_type;
935 return a_info == b_info;942 return a_info == b_info;
...@@ -1192,6 +1199,7 @@ pub const Key = union(enum) {...@@ -1192,6 +1199,7 @@ pub const Key = union(enum) {
1192 .enum_type,1199 .enum_type,
1193 .anon_struct_type,1200 .anon_struct_type,
1194 .func_type,1201 .func_type,
1202 .async_frame_type,
1195 => .type_type,1203 => .type_type,
11961204
1197 inline .runtime_value,1205 inline .runtime_value,
...@@ -1432,6 +1440,7 @@ pub const Index = enum(u32) {...@@ -1432,6 +1440,7 @@ pub const Index = enum(u32) {
1432 trailing: struct { names: []NullTerminatedString },1440 trailing: struct { names: []NullTerminatedString },
1433 },1441 },
1434 type_inferred_error_set: struct { data: Module.Fn.InferredErrorSet.Index },1442 type_inferred_error_set: struct { data: Module.Fn.InferredErrorSet.Index },
1443 type_async_frame: Module.Fn.Index,
1435 type_enum_auto: struct {1444 type_enum_auto: struct {
1436 const @"data.fields_len" = opaque {};1445 const @"data.fields_len" = opaque {};
1437 data: *EnumAuto,1446 data: *EnumAuto,
...@@ -1869,6 +1878,9 @@ pub const Tag = enum(u8) {...@@ -1869,6 +1878,9 @@ pub const Tag = enum(u8) {
1869 /// An untagged union type which has a safety tag.1878 /// An untagged union type which has a safety tag.
1870 /// `data` is `Module.Union.Index`.1879 /// `data` is `Module.Union.Index`.
1871 type_union_safety,1880 type_union_safety,
1881 /// The async frame type of a function.
1882 /// data is `Module.Fn.Index`.
1883 type_async_frame,
1872 /// A function body type.1884 /// A function body type.
1873 /// `data` is extra index to `TypeFunction`.1885 /// `data` is extra index to `TypeFunction`.
1874 type_function,1886 type_function,
...@@ -2059,6 +2071,7 @@ pub const Tag = enum(u8) {...@@ -2059,6 +2071,7 @@ pub const Tag = enum(u8) {
2059 .type_error_union => ErrorUnionType,2071 .type_error_union => ErrorUnionType,
2060 .type_error_set => ErrorSet,2072 .type_error_set => ErrorSet,
2061 .type_inferred_error_set => unreachable,2073 .type_inferred_error_set => unreachable,
2074 .type_async_frame => unreachable,
2062 .type_enum_auto => EnumAuto,2075 .type_enum_auto => EnumAuto,
2063 .type_enum_explicit => EnumExplicit,2076 .type_enum_explicit => EnumExplicit,
2064 .type_enum_nonexhaustive => EnumExplicit,2077 .type_enum_nonexhaustive => EnumExplicit,
...@@ -2636,6 +2649,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -2636,6 +2649,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
2636 .type_inferred_error_set => .{2649 .type_inferred_error_set => .{
2637 .inferred_error_set_type = @as(Module.Fn.InferredErrorSet.Index, @enumFromInt(data)),2650 .inferred_error_set_type = @as(Module.Fn.InferredErrorSet.Index, @enumFromInt(data)),
2638 },2651 },
2652 .type_async_frame => .{ .async_frame_type = @enumFromInt(data) },
26392653
2640 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },2654 .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) },
2641 .type_struct => {2655 .type_struct => {
...@@ -3240,6 +3254,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3240,6 +3254,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3240 .data = @intFromEnum(ies_index),3254 .data = @intFromEnum(ies_index),
3241 });3255 });
3242 },3256 },
3257 .async_frame_type => |fn_index| {
3258 ip.items.appendAssumeCapacity(.{
3259 .tag = .type_async_frame,
3260 .data = @intFromEnum(fn_index),
3261 });
3262 },
3243 .simple_type => |simple_type| {3263 .simple_type => |simple_type| {
3244 ip.items.appendAssumeCapacity(.{3264 ip.items.appendAssumeCapacity(.{
3245 .tag = .simple_type,3265 .tag = .simple_type,
...@@ -5053,6 +5073,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -5053,6 +5073,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
5053 break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len);5073 break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len);
5054 },5074 },
5055 .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet),5075 .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet),
5076 .type_async_frame => 0,
5056 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),5077 .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit),
5057 .type_enum_auto => @sizeOf(EnumAuto),5078 .type_enum_auto => @sizeOf(EnumAuto),
5058 .type_opaque => @sizeOf(Key.OpaqueType),5079 .type_opaque => @sizeOf(Key.OpaqueType),
...@@ -5195,6 +5216,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -5195,6 +5216,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
5195 .type_error_union,5216 .type_error_union,
5196 .type_error_set,5217 .type_error_set,
5197 .type_inferred_error_set,5218 .type_inferred_error_set,
5219 .type_async_frame,
5198 .type_enum_explicit,5220 .type_enum_explicit,
5199 .type_enum_nonexhaustive,5221 .type_enum_nonexhaustive,
5200 .type_enum_auto,5222 .type_enum_auto,
...@@ -5578,6 +5600,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -5578,6 +5600,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
5578 .type_error_union,5600 .type_error_union,
5579 .type_error_set,5601 .type_error_set,
5580 .type_inferred_error_set,5602 .type_inferred_error_set,
5603 .type_async_frame,
5581 .type_enum_auto,5604 .type_enum_auto,
5582 .type_enum_explicit,5605 .type_enum_explicit,
5583 .type_enum_nonexhaustive,5606 .type_enum_nonexhaustive,
...@@ -5926,6 +5949,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -5926,6 +5949,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
5926 => .Union,5949 => .Union,
59275950
5928 .type_function => .Fn,5951 .type_function => .Fn,
5952 .type_async_frame => .Frame,
59295953
5930 // values, not types5954 // values, not types
5931 .undef,5955 .undef,
src/Liveness.zig+74-39
...@@ -484,28 +484,15 @@ pub fn categorizeOperand(...@@ -484,28 +484,15 @@ pub fn categorizeOperand(
484 const inst_data = air_datas[inst].pl_op;484 const inst_data = air_datas[inst].pl_op;
485 const callee = inst_data.operand;485 const callee = inst_data.operand;
486 const extra = air.extraData(Air.Call, inst_data.payload);486 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]));487 const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]);
488 if (args.len + 1 <= bpi - 1) {488 return categorizeOperandCall(l, inst, operand_ref, callee, args);
489 if (callee == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);489 },
490 for (args, 0..) |arg, i| {490 .call_async => {
491 if (arg == operand_ref) return matchOperandSmallIndex(l, inst, @as(OperandInt, @intCast(i + 1)), .write);491 const inst_data = air_datas[inst].ty_pl;
492 }492 const extra = air.extraData(Air.AsyncCall, inst_data.payload);
493 return .write;493 const callee = extra.data.callee;
494 }494 const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]);
495 var bt = l.iterateBigTomb(inst);495 return categorizeOperandCall(l, inst, operand_ref, callee, args);
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;
509 },496 },
510 .select => {497 .select => {
511 const pl_op = air_datas[inst].pl_op;498 const pl_op = air_datas[inst].pl_op;
...@@ -674,6 +661,36 @@ pub fn categorizeOperand(...@@ -674,6 +661,36 @@ pub fn categorizeOperand(
674 }661 }
675}662}
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
677fn matchOperandSmallIndex(694fn matchOperandSmallIndex(
678 l: Liveness,695 l: Liveness,
679 inst: Air.Inst.Index,696 inst: Air.Inst.Index,
...@@ -1108,23 +1125,15 @@ fn analyzeInst(...@@ -1108,23 +1125,15 @@ fn analyzeInst(
1108 const inst_data = inst_datas[inst].pl_op;1125 const inst_data = inst_datas[inst].pl_op;
1109 const callee = inst_data.operand;1126 const callee = inst_data.operand;
1110 const extra = a.air.extraData(Air.Call, inst_data.payload);1127 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]));1128 const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]);
1112 if (args.len + 1 <= bpi - 1) {1129 return analyzeInstCall(a, pass, data, inst, callee, args);
1113 var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);1130 },
1114 buf[0] = callee;1131 .call_async => {
1115 @memcpy(buf[1..][0..args.len], args);1132 const inst_data = inst_datas[inst].ty_pl;
1116 return analyzeOperands(a, pass, data, inst, buf);1133 const extra = a.air.extraData(Air.AsyncCall, inst_data.payload);
1117 }1134 const callee = extra.data.callee;
11181135 const args: []const Air.Inst.Ref = @ptrCast(a.air.extra[extra.end..][0..extra.data.args_len]);
1119 var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1);1136 return analyzeInstCall(a, pass, data, inst, callee, args);
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 },1137 },
1129 .select => {1138 .select => {
1130 const pl_op = inst_datas[inst].pl_op;1139 const pl_op = inst_datas[inst].pl_op;
...@@ -1253,6 +1262,32 @@ fn analyzeInst(...@@ -1253,6 +1262,32 @@ fn analyzeInst(
1253 }1262 }
1254}1263}
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
1256/// Every instruction should hit this (after handling any nested bodies), in every pass. In the1291/// Every instruction should hit this (after handling any nested bodies), in every pass. In the
1257/// initial pass, it is responsible for marking deaths of the (first three) operands and noticing1292/// initial pass, it is responsible for marking deaths of the (first three) operands and noticing
1258/// immediate deaths.1293/// immediate deaths.
src/Liveness/Verify.zig+14
...@@ -349,6 +349,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -349,6 +349,20 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
349 }349 }
350 try self.verifyInst(inst);350 try self.verifyInst(inst);
351 },351 },
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 },
352 .assembly => {366 .assembly => {
353 const ty_pl = data[inst].ty_pl;367 const ty_pl = data[inst].ty_pl;
354 const extra = self.air.extraData(Air.Asm, ty_pl.payload);368 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
src/Module.zig+58
...@@ -1437,6 +1437,7 @@ pub const Fn = struct {...@@ -1437,6 +1437,7 @@ pub const Fn = struct {
1437 generic_owner_decl: Decl.OptionalIndex,1437 generic_owner_decl: Decl.OptionalIndex,
14381438
1439 state: Analysis,1439 state: Analysis,
1440 async_status: AsyncStatus,
1440 is_cold: bool = false,1441 is_cold: bool = false,
1441 is_noinline: bool,1442 is_noinline: bool,
1442 calls_or_awaits_errorable_fn: bool = false,1443 calls_or_awaits_errorable_fn: bool = false,
...@@ -1481,6 +1482,12 @@ pub const Fn = struct {...@@ -1481,6 +1482,12 @@ pub const Fn = struct {
1481 success,1482 success,
1482 };1483 };
14831484
1485 pub const AsyncStatus = enum {
1486 unknown,
1487 yes_async,
1488 not_async,
1489 };
1490
1484 /// This struct is used to keep track of any dependencies related to functions instances1491 /// This struct is used to keep track of any dependencies related to functions instances
1485 /// that return inferred error sets. Note that a function may be associated to1492 /// that return inferred error sets. Note that a function may be associated to
1486 /// multiple different error sets, for example an inferred error set which1493 /// multiple different error sets, for example an inferred error set which
...@@ -1608,6 +1615,14 @@ pub const Fn = struct {...@@ -1608,6 +1615,14 @@ pub const Fn = struct {
1608 else => unreachable,1615 else => unreachable,
1609 }1616 }
1610 }1617 }
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 }
1611};1626};
16121627
1613pub const DeclAdapter = struct {1628pub const DeclAdapter = struct {
...@@ -2340,6 +2355,36 @@ pub const SrcLoc = struct {...@@ -2340,6 +2355,36 @@ pub const SrcLoc = struct {
2340 const full = tree.fullCall(&buf, node).?;2355 const full = tree.fullCall(&buf, node).?;
2341 return nodeToSpan(tree, full.ast.fn_expr);2356 return nodeToSpan(tree, full.ast.fn_expr);
2342 },2357 },
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 },
2343 .node_offset_field_name => |node_off| {2388 .node_offset_field_name => |node_off| {
2344 const tree = try src_loc.file_scope.getTree(gpa);2389 const tree = try src_loc.file_scope.getTree(gpa);
2345 const node_datas = tree.nodes.items(.data);2390 const node_datas = tree.nodes.items(.data);
...@@ -2963,6 +3008,14 @@ pub const LazySrcLoc = union(enum) {...@@ -2963,6 +3008,14 @@ pub const LazySrcLoc = union(enum) {
2963 /// to the callee expression.3008 /// to the callee expression.
2964 /// The Decl is determined contextually.3009 /// The Decl is determined contextually.
2965 node_offset_call_func: i32,3010 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,
2966 /// The payload is offset from the containing Decl AST node.3019 /// The payload is offset from the containing Decl AST node.
2967 /// The source location points to the field name of:3020 /// The source location points to the field name of:
2968 /// * a field access expression (`a.b`), or3021 /// * a field access expression (`a.b`), or
...@@ -3192,6 +3245,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3192,6 +3245,7 @@ pub const LazySrcLoc = union(enum) {
3192 .node_offset_slice_end,3245 .node_offset_slice_end,
3193 .node_offset_slice_sentinel,3246 .node_offset_slice_sentinel,
3194 .node_offset_call_func,3247 .node_offset_call_func,
3248 .node_offset_async_call_func,
3195 .node_offset_field_name,3249 .node_offset_field_name,
3196 .node_offset_deref_ptr,3250 .node_offset_deref_ptr,
3197 .node_offset_asm_source,3251 .node_offset_asm_source,
...@@ -6869,6 +6923,10 @@ pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) A...@@ -6869,6 +6923,10 @@ pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) A
6869 return (try mod.intern_pool.get(mod.gpa, .{ .error_set_type = .{ .names = names } })).toType();6923 return (try mod.intern_pool.get(mod.gpa, .{ .error_set_type = .{ .names = names } })).toType();
6870}6924}
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
6872/// Sorts `names` in place.6930/// Sorts `names` in place.
6873pub fn errorSetFromUnsortedNames(6931pub fn errorSetFromUnsortedNames(
6874 mod: *Module,6932 mod: *Module,
src/Sema.zig+141-46
...@@ -941,8 +941,9 @@ fn analyzeBodyInner(...@@ -941,8 +941,9 @@ fn analyzeBodyInner(
941 .bool_br_and => try sema.zirBoolBr(block, inst, false),941 .bool_br_and => try sema.zirBoolBr(block, inst, false),
942 .bool_br_or => try sema.zirBoolBr(block, inst, true),942 .bool_br_or => try sema.zirBoolBr(block, inst, true),
943 .c_import => try sema.zirCImport(block, inst),943 .c_import => try sema.zirCImport(block, inst),
944 .call => try sema.zirCall(block, inst, .direct),944 .call => try sema.zirCall(block, inst, Zir.Inst.Call),
945 .field_call => try sema.zirCall(block, inst, .field),945 .field_call => try sema.zirCall(block, inst, Zir.Inst.FieldCall),
946 .async_call => try sema.zirAsyncCall(block, inst),
946 .closure_get => try sema.zirClosureGet(block, inst),947 .closure_get => try sema.zirClosureGet(block, inst),
947 .cmp_lt => try sema.zirCmp(block, inst, .lt),948 .cmp_lt => try sema.zirCmp(block, inst, .lt),
948 .cmp_lte => try sema.zirCmp(block, inst, .lte),949 .cmp_lte => try sema.zirCmp(block, inst, .lte),
...@@ -6435,7 +6436,7 @@ fn zirCall(...@@ -6435,7 +6436,7 @@ fn zirCall(
6435 sema: *Sema,6436 sema: *Sema,
6436 block: *Block,6437 block: *Block,
6437 inst: Zir.Inst.Index,6438 inst: Zir.Inst.Index,
6438 comptime kind: enum { direct, field },6439 comptime ExtraType: type,
6439) CompileError!Air.Inst.Ref {6440) CompileError!Air.Inst.Ref {
6440 const tracy = trace(@src());6441 const tracy = trace(@src());
6441 defer tracy.end();6442 defer tracy.end();
...@@ -6444,10 +6445,6 @@ fn zirCall(...@@ -6444,10 +6445,6 @@ fn zirCall(
6444 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;6445 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6445 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };6446 const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
6446 const call_src = inst_data.src();6447 const call_src = inst_data.src();
6447 const ExtraType = switch (kind) {
6448 .direct => Zir.Inst.Call,
6449 .field => Zir.Inst.FieldCall,
6450 };
6451 const extra = sema.code.extraData(ExtraType, inst_data.payload_index);6448 const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
6452 const args_len = extra.data.flags.args_len;6449 const args_len = extra.data.flags.args_len;
64536450
...@@ -6455,38 +6452,90 @@ fn zirCall(...@@ -6455,38 +6452,90 @@ fn zirCall(
6455 const ensure_result_used = extra.data.flags.ensure_result_used;6452 const ensure_result_used = extra.data.flags.ensure_result_used;
6456 const pop_error_return_trace = extra.data.flags.pop_error_return_trace;6453 const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
64576454
6458 const callee: ResolvedFieldCallee = switch (kind) {6455 const callee: ResolvedFieldCallee = switch (ExtraType) {
6459 .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },6456 Zir.Inst.Call => .{ .direct = try sema.resolveInst(extra.data.callee) },
6460 .field => blk: {6457 Zir.Inst.FieldCall => blk: {
6461 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);6458 const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
6462 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));6459 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));
6463 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };6460 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
6464 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);6461 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
6465 },6462 },
6463 else => @compileError("unreachable"),
6466 };6464 };
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
6467 var resolved_args: []Air.Inst.Ref = undefined;6517 var resolved_args: []Air.Inst.Ref = undefined;
6468 var bound_arg_src: ?LazySrcLoc = null;6518 var bound_arg_src: ?LazySrcLoc = null;
6469 var func: Air.Inst.Ref = undefined;
6470 var arg_index: u32 = 0;6519 var arg_index: u32 = 0;
6471 switch (callee) {6520 const func: Air.Inst.Ref = switch (callee) {
6472 .direct => |func_inst| {6521 .direct => |func_inst| f: {
6473 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);6522 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
6474 func = func_inst;6523 break :f func_inst;
6475 },6524 },
6476 .method => |method| {6525 .method => |method| f: {
6477 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);6526 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
6478 func = method.func_inst;
6479 resolved_args[0] = method.arg0_inst;6527 resolved_args[0] = method.arg0_inst;
6480 arg_index += 1;6528 arg_index += 1;
6481 bound_arg_src = callee_src;6529 bound_arg_src = callee_src;
6530 break :f method.func_inst;
6482 },6531 },
6483 }6532 };
64846533
6485 const callee_ty = sema.typeOf(func);6534 const callee_ty = sema.typeOf(func);
6486 const total_args = args_len + @intFromBool(bound_arg_src != null);6535 const total_args = args_len + @intFromBool(bound_arg_src != null);
6487 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);6536 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
6491 var input_is_error = false;6540 var input_is_error = false;
6492 const block_index = @as(Air.Inst.Index, @intCast(block.instructions.items.len));6541 const block_index = @as(Air.Inst.Index, @intCast(block.instructions.items.len));
...@@ -6501,7 +6550,7 @@ fn zirCall(...@@ -6501,7 +6550,7 @@ fn zirCall(
6501 arg_index += 1;6550 arg_index += 1;
6502 }) {6551 }) {
6503 const func_ty_info = mod.typeToFunc(func_ty).?;6552 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];
6505 defer arg_start = arg_end;6554 defer arg_start = arg_end;
65066555
6507 // Generate args to comptime params in comptime block.6556 // Generate args to comptime params in comptime block.
...@@ -6730,8 +6779,7 @@ fn analyzeCall(...@@ -6730,8 +6779,7 @@ fn analyzeCall(
6730 .never_tail => Air.Inst.Tag.call_never_tail,6779 .never_tail => Air.Inst.Tag.call_never_tail,
6731 .never_inline => Air.Inst.Tag.call_never_inline,6780 .never_inline => Air.Inst.Tag.call_never_inline,
6732 .always_tail => Air.Inst.Tag.call_always_tail,6781 .always_tail => Air.Inst.Tag.call_always_tail,
67336782 .async_kw => Air.Inst.Tag.call_async,
6734 .async_kw => return sema.failWithUseOfAsync(block, call_src),
6735 };6783 };
67366784
6737 if (modifier == .never_inline and func_ty_info.cc == .Inline) {6785 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
...@@ -7158,18 +7206,20 @@ fn analyzeCall(...@@ -7158,18 +7206,20 @@ fn analyzeCall(
7158 }7206 }
7159 }7207 }
71607208
7161 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +7209 if (call_tag == .call_async) {
7162 args.len);7210 const func_val = sema.resolveConstValue(block, func_src, func, "function is not comptime-known; @asyncCall required") catch |err| {
7163 const func_inst = try block.addInst(.{7211 if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err);
7164 .tag = call_tag,7212 return err;
7165 .data = .{ .pl_op = .{7213 };
7166 .operand = func,7214 const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
7167 .payload = sema.addExtraAssumeCapacity(Air.Call{7215 .func => |function| function.index,
7168 .args_len = @as(u32, @intCast(args.len)),7216 .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?,
7169 }),7217 else => unreachable,
7170 } },7218 };
7171 });7219 break :res try addAsyncCallInst(sema, block, func, module_fn_index, args);
7172 sema.appendRefsAssumeCapacity(args);7220 }
7221
7222 const func_inst = try addCallInst(sema, block, func, args, call_tag);
71737223
7174 if (call_tag == .call_always_tail) {7224 if (call_tag == .call_always_tail) {
7175 if (ensure_result_used) {7225 if (ensure_result_used) {
...@@ -7206,6 +7256,56 @@ fn analyzeCall(...@@ -7206,6 +7256,56 @@ fn analyzeCall(
7206 return result;7256 return result;
7207}7257}
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
7209fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {7309fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
7210 const mod = sema.mod;7310 const mod = sema.mod;
7211 const target = mod.getTarget();7311 const target = mod.getTarget();
...@@ -7664,19 +7764,10 @@ fn instantiateGenericCall(...@@ -7664,19 +7764,10 @@ fn instantiateGenericCall(
7664 }7764 }
76657765
7666 try mod.ensureFuncBodyAnalysisQueued(callee_index);7766 try mod.ensureFuncBodyAnalysisQueued(callee_index);
76677767 const result = switch (call_tag) {
7668 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +7768 .call_async => try addAsyncCallInst(sema, block, callee_inst, callee_index, runtime_args),
7669 runtime_args_len);7769 else => try addCallInst(sema, block, callee_inst, runtime_args, call_tag),
7670 const result = try block.addInst(.{7770 };
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);
76807771
7681 if (ensure_result_used) {7772 if (ensure_result_used) {
7682 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);7773 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
...@@ -9221,6 +9312,7 @@ fn funcCommon(...@@ -9221,6 +9312,7 @@ fn funcCommon(
9221 const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;9312 const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
9222 new_func.* = .{9313 new_func.* = .{
9223 .state = anal_state,9314 .state = anal_state,
9315 .async_status = .unknown,
9224 .zir_body_inst = func_inst,9316 .zir_body_inst = func_inst,
9225 .owner_decl = sema.owner_decl_index,9317 .owner_decl = sema.owner_decl_index,
9226 .generic_owner_decl = generic_owner_decl,9318 .generic_owner_decl = generic_owner_decl,
...@@ -33730,6 +33822,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33730,6 +33822,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33730 .error_set_type, .inferred_error_set_type => false,33822 .error_set_type, .inferred_error_set_type => false,
3373133823
33732 .func_type => true,33824 .func_type => true,
33825 .async_frame_type => false,
3373333826
33734 .simple_type => |t| switch (t) {33827 .simple_type => |t| switch (t) {
33735 .f16,33828 .f16,
...@@ -35271,6 +35364,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -35271,6 +35364,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
35271 .type_inferred_error_set,35364 .type_inferred_error_set,
35272 .type_opaque,35365 .type_opaque,
35273 .type_function,35366 .type_function,
35367 .type_async_frame,
35274 => null,35368 => null,
35275 .simple_type, // handled above35369 .simple_type, // handled above
35276 // values, not types35370 // values, not types
...@@ -35934,6 +36028,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -35934,6 +36028,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
35934 },36028 },
3593536029
35936 .opaque_type => false,36030 .opaque_type => false,
36031 .async_frame_type => false,
35937 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),36032 .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
3593836033
35939 // values, not types36034 // values, not types
src/TypedValue.zig+1
...@@ -192,6 +192,7 @@ pub fn print(...@@ -192,6 +192,7 @@ pub fn print(
192 .func_type,192 .func_type,
193 .error_set_type,193 .error_set_type,
194 .inferred_error_set_type,194 .inferred_error_set_type,
195 .async_frame_type,
195 => return Type.print(val.toType(), writer, mod),196 => return Type.print(val.toType(), writer, mod),
196 .undef => return writer.writeAll("undefined"),197 .undef => return writer.writeAll("undefined"),
197 .runtime_value => return writer.writeAll("(runtime value)"),198 .runtime_value => return writer.writeAll("(runtime value)"),
src/Zir.zig+21-2
...@@ -313,6 +313,11 @@ pub const Inst = struct {...@@ -313,6 +313,11 @@ pub const Inst = struct {
313 /// Uses the `pl_node` union field with payload `BuiltinCall`.313 /// Uses the `pl_node` union field with payload `BuiltinCall`.
314 /// AST node is the builtin call.314 /// AST node is the builtin call.
315 builtin_call,315 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,
316 /// `<`321 /// `<`
317 /// Uses the `pl_node` union field. Payload is `Bin`.322 /// Uses the `pl_node` union field. Payload is `Bin`.
318 cmp_lt,323 cmp_lt,
...@@ -1026,6 +1031,7 @@ pub const Inst = struct {...@@ -1026,6 +1031,7 @@ pub const Inst = struct {
1026 .bool_not,1031 .bool_not,
1027 .call,1032 .call,
1028 .field_call,1033 .field_call,
1034 .async_call,
1029 .cmp_lt,1035 .cmp_lt,
1030 .cmp_lte,1036 .cmp_lte,
1031 .cmp_eq,1037 .cmp_eq,
...@@ -1330,6 +1336,7 @@ pub const Inst = struct {...@@ -1330,6 +1336,7 @@ pub const Inst = struct {
1330 .bool_not,1336 .bool_not,
1331 .call,1337 .call,
1332 .field_call,1338 .field_call,
1339 .async_call,
1333 .cmp_lt,1340 .cmp_lt,
1334 .cmp_lte,1341 .cmp_lte,
1335 .cmp_eq,1342 .cmp_eq,
...@@ -1564,6 +1571,7 @@ pub const Inst = struct {...@@ -1564,6 +1571,7 @@ pub const Inst = struct {
1564 .for_len = .pl_node,1571 .for_len = .pl_node,
1565 .call = .pl_node,1572 .call = .pl_node,
1566 .field_call = .pl_node,1573 .field_call = .pl_node,
1574 .async_call = .pl_node,
1567 .cmp_lt = .pl_node,1575 .cmp_lt = .pl_node,
1568 .cmp_lte = .pl_node,1576 .cmp_lte = .pl_node,
1569 .cmp_eq = .pl_node,1577 .cmp_eq = .pl_node,
...@@ -1944,7 +1952,7 @@ pub const Inst = struct {...@@ -1944,7 +1952,7 @@ pub const Inst = struct {
1944 /// `small` contains `NameStrategy`.1952 /// `small` contains `NameStrategy`.
1945 reify,1953 reify,
1946 /// Implements the `@asyncCall` builtin.1954 /// Implements the `@asyncCall` builtin.
1947 /// `operand` is payload index to `AsyncCall`.1955 /// `operand` is payload index to `BuiltinAsyncCall`.
1948 builtin_async_call,1956 builtin_async_call,
1949 /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins.1957 /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins.
1950 /// `small` 0=>weak 1=>strong1958 /// `small` 0=>weak 1=>strong
...@@ -2531,6 +2539,16 @@ pub const Inst = struct {...@@ -2531,6 +2539,16 @@ pub const Inst = struct {
2531 field_name_start: u32,2539 field_name_start: u32,
2532 };2540 };
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
2534 pub const TypeOfPeer = struct {2552 pub const TypeOfPeer = struct {
2535 src_node: i32,2553 src_node: i32,
2536 body_len: u32,2554 body_len: u32,
...@@ -3101,7 +3119,8 @@ pub const Inst = struct {...@@ -3101,7 +3119,8 @@ pub const Inst = struct {
3101 b: Ref,3119 b: Ref,
3102 };3120 };
31033121
3104 pub const AsyncCall = struct {3122 /// Not to be confused with AsyncCall.
3123 pub const BuiltinAsyncCall = struct {
3105 node: i32,3124 node: i32,
3106 frame_buffer: Ref,3125 frame_buffer: Ref,
3107 result_ptr: Ref,3126 result_ptr: Ref,
src/arch/aarch64/CodeGen.zig+2
...@@ -819,6 +819,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -819,6 +819,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
819 .call_always_tail => try self.airCall(inst, .always_tail),819 .call_always_tail => try self.airCall(inst, .always_tail),
820 .call_never_tail => try self.airCall(inst, .never_tail),820 .call_never_tail => try self.airCall(inst, .never_tail),
821 .call_never_inline => try self.airCall(inst, .never_inline),821 .call_never_inline => try self.airCall(inst, .never_inline),
822 .call_async => try self.airCall(inst, .async_kw),
822823
823 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),824 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
824 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),825 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -4242,6 +4243,7 @@ fn airFence(self: *Self) !void {...@@ -4242,6 +4243,7 @@ fn airFence(self: *Self) !void {
42424243
4243fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4244fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4244 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});4245 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", .{});
4245 const pl_op = self.air.instructions.items(.data)[inst].pl_op;4247 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4246 const callee = pl_op.operand;4248 const callee = pl_op.operand;
4247 const extra = self.air.extraData(Air.Call, pl_op.payload);4249 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 {...@@ -803,6 +803,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
803 .call_always_tail => try self.airCall(inst, .always_tail),803 .call_always_tail => try self.airCall(inst, .always_tail),
804 .call_never_tail => try self.airCall(inst, .never_tail),804 .call_never_tail => try self.airCall(inst, .never_tail),
805 .call_never_inline => try self.airCall(inst, .never_inline),805 .call_never_inline => try self.airCall(inst, .never_inline),
806 .call_async => try self.airCall(inst, .async_kw),
806807
807 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),808 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
808 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),809 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -4215,6 +4216,7 @@ fn airFence(self: *Self) !void {...@@ -4215,6 +4216,7 @@ fn airFence(self: *Self) !void {
42154216
4216fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4217fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4217 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});4218 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", .{});
4218 const pl_op = self.air.instructions.items(.data)[inst].pl_op;4220 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4219 const callee = pl_op.operand;4221 const callee = pl_op.operand;
4220 const extra = self.air.extraData(Air.Call, pl_op.payload);4222 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 {...@@ -638,6 +638,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
638 .call_always_tail => try self.airCall(inst, .always_tail),638 .call_always_tail => try self.airCall(inst, .always_tail),
639 .call_never_tail => try self.airCall(inst, .never_tail),639 .call_never_tail => try self.airCall(inst, .never_tail),
640 .call_never_inline => try self.airCall(inst, .never_inline),640 .call_never_inline => try self.airCall(inst, .never_inline),
641 .call_async => try self.airCall(inst, .async_kw),
641642
642 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),643 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
643 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),644 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -1707,6 +1708,7 @@ fn airFence(self: *Self) !void {...@@ -1707,6 +1708,7 @@ fn airFence(self: *Self) !void {
1707fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {1708fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
1708 const mod = self.bin_file.options.module.?;1709 const mod = self.bin_file.options.module.?;
1709 if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{});1710 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", .{});
1710 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1712 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1711 const fn_ty = self.typeOf(pl_op.operand);1713 const fn_ty = self.typeOf(pl_op.operand);
1712 const callee = pl_op.operand;1714 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 {...@@ -651,6 +651,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
651 .call_always_tail => try self.airCall(inst, .always_tail),651 .call_always_tail => try self.airCall(inst, .always_tail),
652 .call_never_tail => try self.airCall(inst, .never_tail),652 .call_never_tail => try self.airCall(inst, .never_tail),
653 .call_never_inline => try self.airCall(inst, .never_inline),653 .call_never_inline => try self.airCall(inst, .never_inline),
654 .call_async => try self.airCall(inst, .async_kw),
654655
655 .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"),656 .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"),
656 .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"),657 .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"),
...@@ -1293,6 +1294,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {...@@ -1293,6 +1294,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
12931294
1294fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {1295fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
1295 if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});1296 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
1297 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1299 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1298 const callee = pl_op.operand;1300 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 {...@@ -1930,6 +1930,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1930 .call_always_tail => func.airCall(inst, .always_tail),1930 .call_always_tail => func.airCall(inst, .always_tail),
1931 .call_never_tail => func.airCall(inst, .never_tail),1931 .call_never_tail => func.airCall(inst, .never_tail),
1932 .call_never_inline => func.airCall(inst, .never_inline),1932 .call_never_inline => func.airCall(inst, .never_inline),
1933 .call_async => func.airCall(inst, .async_kw),
19331934
1934 .is_err => func.airIsErr(inst, .i32_ne),1935 .is_err => func.airIsErr(inst, .i32_ne),
1935 .is_non_err => func.airIsErr(inst, .i32_eq),1936 .is_non_err => func.airIsErr(inst, .i32_eq),
...@@ -2180,6 +2181,7 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2180,6 +2181,7 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21802181
2181fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {2182fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
2182 if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{});2183 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", .{});
2183 const pl_op = func.air.instructions.items(.data)[inst].pl_op;2185 const pl_op = func.air.instructions.items(.data)[inst].pl_op;
2184 const extra = func.air.extraData(Air.Call, pl_op.payload);2186 const extra = func.air.extraData(Air.Call, pl_op.payload);
2185 const args = @as([]const Air.Inst.Ref, @ptrCast(func.air.extra[extra.end..][0..extra.data.args_len]));2187 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 {...@@ -3125,6 +3127,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3125 .func_type,3127 .func_type,
3126 .error_set_type,3128 .error_set_type,
3127 .inferred_error_set_type,3129 .inferred_error_set_type,
3130 .async_frame_type,
3128 => unreachable, // types, not values3131 => unreachable, // types, not values
31293132
3130 .undef, .runtime_value => unreachable, // handled above3133 .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 {...@@ -1901,6 +1901,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1901 .call_always_tail => try self.airCall(inst, .always_tail),1901 .call_always_tail => try self.airCall(inst, .always_tail),
1902 .call_never_tail => try self.airCall(inst, .never_tail),1902 .call_never_tail => try self.airCall(inst, .never_tail),
1903 .call_never_inline => try self.airCall(inst, .never_inline),1903 .call_never_inline => try self.airCall(inst, .never_inline),
1904 .call_async => try self.airCall(inst, .async_kw),
19041905
1905 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),1906 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
1906 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),1907 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
...@@ -8059,6 +8060,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {...@@ -8059,6 +8060,7 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
8059fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {8060fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
8060 const mod = self.bin_file.options.module.?;8061 const mod = self.bin_file.options.module.?;
8061 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});8062 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", .{});
8062 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8064 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
8063 const callee = pl_op.operand;8065 const callee = pl_op.operand;
8064 const extra = self.air.extraData(Air.Call, pl_op.payload);8066 const extra = self.air.extraData(Air.Call, pl_op.payload);
src/codegen.zig+1
...@@ -222,6 +222,7 @@ pub fn generateSymbol(...@@ -222,6 +222,7 @@ pub fn generateSymbol(
222 .func_type,222 .func_type,
223 .error_set_type,223 .error_set_type,
224 .inferred_error_set_type,224 .inferred_error_set_type,
225 .async_frame_type,
225 => unreachable, // types, not values226 => unreachable, // types, not values
226227
227 .undef, .runtime_value => unreachable, // handled above228 .undef, .runtime_value => unreachable, // handled above
src/codegen/c.zig+2
...@@ -927,6 +927,7 @@ pub const DeclGen = struct {...@@ -927,6 +927,7 @@ pub const DeclGen = struct {
927 .func_type,927 .func_type,
928 .error_set_type,928 .error_set_type,
929 .inferred_error_set_type,929 .inferred_error_set_type,
930 .async_frame_type,
930 // memoization, not values931 // memoization, not values
931 .memoized_call,932 .memoized_call,
932 => unreachable,933 => unreachable,
...@@ -2999,6 +3000,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2999,6 +3000,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2999 .call_always_tail => .none,3000 .call_always_tail => .none,
3000 .call_never_tail => try airCall(f, inst, .never_tail),3001 .call_never_tail => try airCall(f, inst, .never_tail),
3001 .call_never_inline => try airCall(f, inst, .never_inline),3002 .call_never_inline => try airCall(f, inst, .never_inline),
3003 .call_async => try airCall(f, inst, .async_kw),
30023004
3003 .float_from_int,3005 .float_from_int,
3004 .int_from_float,3006 .int_from_float,
src/codegen/llvm.zig+56-2
...@@ -3017,11 +3017,58 @@ pub const Object = struct {...@@ -3017,11 +3017,58 @@ pub const Object = struct {
3017 .Null => unreachable,3017 .Null => unreachable,
3018 .EnumLiteral => unreachable,3018 .EnumLiteral => unreachable,
30193019
3020 .Frame => @panic("TODO implement llvmType for Frame types"),3020 .Frame => {
3021 .AnyFrame => @panic("TODO implement llvmType for AnyFrame types"),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),
3022 }3046 }
3023 }3047 }
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
3025 fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {3072 fn lowerTypeFn(o: *Object, fn_ty: Type) Allocator.Error!*llvm.Type {
3026 const mod = o.module;3073 const mod = o.module;
3027 const fn_info = mod.typeToFunc(fn_ty).?;3074 const fn_info = mod.typeToFunc(fn_ty).?;
...@@ -3148,6 +3195,7 @@ pub const Object = struct {...@@ -3148,6 +3195,7 @@ pub const Object = struct {
3148 .func_type,3195 .func_type,
3149 .error_set_type,3196 .error_set_type,
3150 .inferred_error_set_type,3197 .inferred_error_set_type,
3198 .async_frame_type,
3151 => unreachable, // types, not values3199 => unreachable, // types, not values
31523200
3153 .undef, .runtime_value => unreachable, // handled above3201 .undef, .runtime_value => unreachable, // handled above
...@@ -4474,6 +4522,7 @@ pub const FuncGen = struct {...@@ -4474,6 +4522,7 @@ pub const FuncGen = struct {
4474 .call_always_tail => try self.airCall(inst, .AlwaysTail),4522 .call_always_tail => try self.airCall(inst, .AlwaysTail),
4475 .call_never_tail => try self.airCall(inst, .NeverTail),4523 .call_never_tail => try self.airCall(inst, .NeverTail),
4476 .call_never_inline => try self.airCall(inst, .NeverInline),4524 .call_never_inline => try self.airCall(inst, .NeverInline),
4525 .call_async => try self.airCallAsync(inst),
44774526
4478 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),4527 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
4479 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),4528 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
...@@ -4939,6 +4988,11 @@ pub const FuncGen = struct {...@@ -4939,6 +4988,11 @@ pub const FuncGen = struct {
4939 _ = fg.builder.buildUnreachable();4988 _ = fg.builder.buildUnreachable();
4940 }4989 }
49414990
4991 fn airCallAsync(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
4992 _ = inst;
4993 return self.todo("lower async call", .{});
4994 }
4995
4942 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {4996 fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
4943 const o = self.dg.object;4997 const o = self.dg.object;
4944 const mod = o.module;4998 const mod = o.module;
src/codegen/spirv.zig+1
...@@ -642,6 +642,7 @@ pub const DeclGen = struct {...@@ -642,6 +642,7 @@ pub const DeclGen = struct {
642 .func_type,642 .func_type,
643 .error_set_type,643 .error_set_type,
644 .inferred_error_set_type,644 .inferred_error_set_type,
645 .async_frame_type,
645 => unreachable, // types, not values646 => unreachable, // types, not values
646647
647 .undef, .runtime_value => unreachable, // handled above648 .undef, .runtime_value => unreachable, // handled above
src/print_air.zig+21-2
...@@ -329,6 +329,7 @@ const Writer = struct {...@@ -329,6 +329,7 @@ const Writer = struct {
329 .reduce, .reduce_optimized => try w.writeReduce(s, inst),329 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
330 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),330 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
331 .vector_store_elem => try w.writeVectorStoreElem(s, inst),331 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
332 .call_async => try w.writeCallAsync(s, inst),
332333
333 .dbg_block_begin, .dbg_block_end => {},334 .dbg_block_begin, .dbg_block_end => {},
334335
...@@ -699,8 +700,26 @@ const Writer = struct {...@@ -699,8 +700,26 @@ const Writer = struct {
699 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {700 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
700 const pl_op = w.air.instructions.items(.data)[inst].pl_op;701 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
701 const extra = w.air.extraData(Air.Call, pl_op.payload);702 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 const args: []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);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);
704 try s.writeAll(", [");723 try s.writeAll(", [");
705 for (args, 0..) |arg, i| {724 for (args, 0..) |arg, i| {
706 if (i != 0) try s.writeAll(", ");725 if (i != 0) try s.writeAll(", ");
src/print_zir.zig+31-5
...@@ -362,6 +362,7 @@ const Writer = struct {...@@ -362,6 +362,7 @@ const Writer = struct {
362362
363 .call => try self.writeCall(stream, inst, .direct),363 .call => try self.writeCall(stream, inst, .direct),
364 .field_call => try self.writeCall(stream, inst, .field),364 .field_call => try self.writeCall(stream, inst, .field),
365 .async_call => try self.writeAsyncCall(stream, inst),
365366
366 .block,367 .block,
367 .block_comptime,368 .block_comptime,
...@@ -837,7 +838,7 @@ const Writer = struct {...@@ -837,7 +838,7 @@ const Writer = struct {
837 }838 }
838839
839 fn writeBuiltinAsyncCall(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {840 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;
841 try self.writeInstRef(stream, extra.frame_buffer);842 try self.writeInstRef(stream, extra.frame_buffer);
842 try stream.writeAll(", ");843 try stream.writeAll(", ");
843 try self.writeInstRef(stream, extra.result_ptr);844 try self.writeInstRef(stream, extra.result_ptr);
...@@ -1187,11 +1188,13 @@ const Writer = struct {...@@ -1187,11 +1188,13 @@ const Writer = struct {
1187 try self.writeSrc(stream, src);1188 try self.writeSrc(stream, src);
1188 }1189 }
11891190
1191 const CallKind = enum { direct, field };
1192
1190 fn writeCall(1193 fn writeCall(
1191 self: *Writer,1194 self: *Writer,
1192 stream: anytype,1195 stream: anytype,
1193 inst: Zir.Inst.Index,1196 inst: Zir.Inst.Index,
1194 comptime kind: enum { direct, field },1197 comptime kind: CallKind,
1195 ) !void {1198 ) !void {
1196 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1199 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1197 const ExtraType = switch (kind) {1200 const ExtraType = switch (kind) {
...@@ -1201,11 +1204,12 @@ const Writer = struct {...@@ -1201,11 +1204,12 @@ const Writer = struct {
1201 const extra = self.code.extraData(ExtraType, inst_data.payload_index);1204 const extra = self.code.extraData(ExtraType, inst_data.payload_index);
1202 const args_len = extra.data.flags.args_len;1205 const args_len = extra.data.flags.args_len;
1203 const body = self.code.extra[extra.end..];1206 const body = self.code.extra[extra.end..];
1207 const modifier: std.builtin.CallModifier = @enumFromInt(extra.data.flags.packed_modifier);
12041208
1205 if (extra.data.flags.ensure_result_used) {1209 if (extra.data.flags.ensure_result_used) {
1206 try stream.writeAll("nodiscard ");1210 try stream.writeAll("nodiscard ");
1207 }1211 }
1208 try stream.print(".{s}, ", .{@tagName(@as(std.builtin.CallModifier, @enumFromInt(extra.data.flags.packed_modifier)))});1212 try stream.print(".{s}, ", .{@tagName(modifier)});
1209 switch (kind) {1213 switch (kind) {
1210 .direct => try self.writeInstRef(stream, extra.data.callee),1214 .direct => try self.writeInstRef(stream, extra.data.callee),
1211 .field => {1215 .field => {
...@@ -1214,6 +1218,28 @@ const Writer = struct {...@@ -1214,6 +1218,28 @@ const Writer = struct {
1214 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});1218 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});
1215 },1219 },
1216 }1220 }
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 {
1217 try stream.writeAll(", [");1243 try stream.writeAll(", [");
12181244
1219 self.indent += 2;1245 self.indent += 2;
...@@ -1224,7 +1250,7 @@ const Writer = struct {...@@ -1224,7 +1250,7 @@ const Writer = struct {
1224 var arg_start: u32 = args_len;1250 var arg_start: u32 = args_len;
1225 while (i < args_len) : (i += 1) {1251 while (i < args_len) : (i += 1) {
1226 try stream.writeByteNTimes(' ', self.indent);1252 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];
1228 defer arg_start = arg_end;1254 defer arg_start = arg_end;
1229 const arg_body = body[arg_start..arg_end];1255 const arg_body = body[arg_start..arg_end];
1230 try self.writeBracedBody(stream, arg_body);1256 try self.writeBracedBody(stream, arg_body);
...@@ -1237,7 +1263,7 @@ const Writer = struct {...@@ -1237,7 +1263,7 @@ const Writer = struct {
1237 }1263 }
12381264
1239 try stream.writeAll("]) ");1265 try stream.writeAll("]) ");
1240 try self.writeSrc(stream, inst_data.src());1266 try self.writeSrc(stream, src);
1241 }1267 }
12421268
1243 fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {1269 fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
src/type.zig+38-1
...@@ -409,6 +409,13 @@ pub const Type = struct {...@@ -409,6 +409,13 @@ pub const Type = struct {
409 try writer.writeAll("anyframe->");409 try writer.writeAll("anyframe->");
410 return print(child.toType(), writer, mod);410 return print(child.toType(), writer, mod);
411 },411 },
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
413 // values, not types420 // values, not types
414 .undef,421 .undef,
...@@ -506,6 +513,7 @@ pub const Type = struct {...@@ -506,6 +513,7 @@ pub const Type = struct {
506 .error_union_type,513 .error_union_type,
507 .error_set_type,514 .error_set_type,
508 .inferred_error_set_type,515 .inferred_error_set_type,
516 .async_frame_type,
509 => true,517 => true,
510518
511 // These are function *bodies*, not pointers.519 // These are function *bodies*, not pointers.
...@@ -666,6 +674,7 @@ pub const Type = struct {...@@ -666,6 +674,7 @@ pub const Type = struct {
666 .anon_struct_type,674 .anon_struct_type,
667 .opaque_type,675 .opaque_type,
668 .anyframe_type,676 .anyframe_type,
677 .async_frame_type,
669 // These are function bodies, not function pointers.678 // These are function bodies, not function pointers.
670 .func_type,679 .func_type,
671 => false,680 => false,
...@@ -1068,6 +1077,9 @@ pub const Type = struct {...@@ -1068,6 +1077,9 @@ pub const Type = struct {
1068 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },1077 .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
1069 .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },1078 .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
1071 // values, not types1083 // values, not types
1072 .undef,1084 .undef,
1073 .runtime_value,1085 .runtime_value,
...@@ -1484,6 +1496,25 @@ pub const Type = struct {...@@ -1484,6 +1496,25 @@ pub const Type = struct {
1484 .opaque_type => unreachable, // no size available1496 .opaque_type => unreachable, // no size available
1485 .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },1497 .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
1487 // values, not types1518 // values, not types
1488 .undef,1519 .undef,
1489 .runtime_value,1520 .runtime_value,
...@@ -1509,7 +1540,7 @@ pub const Type = struct {...@@ -1509,7 +1540,7 @@ pub const Type = struct {
1509 }1540 }
1510 }1541 }
15111542
1512 pub fn abiSizeAdvancedUnion(1543 fn abiSizeAdvancedUnion(
1513 ty: Type,1544 ty: Type,
1514 mod: *Module,1545 mod: *Module,
1515 strat: AbiAlignmentAdvancedStrat,1546 strat: AbiAlignmentAdvancedStrat,
...@@ -1717,6 +1748,9 @@ pub const Type = struct {...@@ -1717,6 +1748,9 @@ pub const Type = struct {
1717 },1748 },
1718 .opaque_type => unreachable,1749 .opaque_type => unreachable,
1719 .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema),1750 .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
1721 // values, not types1755 // values, not types
1722 .undef,1756 .undef,
...@@ -2263,6 +2297,7 @@ pub const Type = struct {...@@ -2263,6 +2297,7 @@ pub const Type = struct {
22632297
2264 .ptr_type => unreachable,2298 .ptr_type => unreachable,
2265 .anyframe_type => unreachable,2299 .anyframe_type => unreachable,
2300 .async_frame_type => unreachable,
2266 .array_type => unreachable,2301 .array_type => unreachable,
22672302
2268 .opt_type => unreachable,2303 .opt_type => unreachable,
...@@ -2445,6 +2480,7 @@ pub const Type = struct {...@@ -2445,6 +2480,7 @@ pub const Type = struct {
2445 .anyframe_type,2480 .anyframe_type,
2446 .error_set_type,2481 .error_set_type,
2447 .inferred_error_set_type,2482 .inferred_error_set_type,
2483 .async_frame_type,
2448 => return null,2484 => return null,
24492485
2450 inline .array_type, .vector_type => |seq_type, seq_tag| {2486 inline .array_type, .vector_type => |seq_type, seq_tag| {
...@@ -2760,6 +2796,7 @@ pub const Type = struct {...@@ -2760,6 +2796,7 @@ pub const Type = struct {
2760 },2796 },
27612797
2762 .opaque_type => false,2798 .opaque_type => false,
2799 .async_frame_type => false,
27632800
2764 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),2801 .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
27652802
src/value.zig+1
...@@ -349,6 +349,7 @@ pub const Value = struct {...@@ -349,6 +349,7 @@ pub const Value = struct {
349 .func_type,349 .func_type,
350 .error_set_type,350 .error_set_type,
351 .inferred_error_set_type,351 .inferred_error_set_type,
352 .async_frame_type,
352353
353 .undef,354 .undef,
354 .runtime_value,355 .runtime_value,