| author | |
| committer | |
| log | 5a8c445779b3b87ba38fbcac0efcc7ebb3787161 |
| tree | f83e02739497a46928bb2c7baa36657f486d2294 |
| parent | 7322aa118376a635ab077ca833dd152639953337 |
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 | }; |
| 1072 | 1075 | ||
| 1076 | /// Trailing is a list of `Inst.Ref` for every `args_len`. | ||
| 1077 | pub 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), |
| 1344 | 1354 | ||
| 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, |
| 2792 | 2793 | ||
| 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 indicate | 209 | /// `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)), |
| 716 | 719 | ||
| ... | @@ -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, |
| 1196 | 1204 | ||
| 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) }, | ||
| 2639 | 2653 | ||
| 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, |
| 5927 | 5950 | ||
| 5928 | .type_function => .Fn, | 5951 | .type_function => .Fn, |
| 5952 | .type_async_frame => .Frame, | ||
| 5929 | 5953 | ||
| 5930 | // values, not types | 5954 | // 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 | } |
| 676 | 663 | ||
| 664 | fn 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 | |||
| 677 | fn matchOperandSmallIndex( | 694 | fn 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; |
| 1118 | 1135 | 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 | } |
| 1255 | 1264 | ||
| 1265 | fn 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 the | 1291 | /// 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 noticing | 1292 | /// 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, |
| 1438 | 1438 | ||
| 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 | }; |
| 1483 | 1484 | ||
| 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 instances | 1491 | /// 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 to | 1492 | /// that return inferred error sets. Note that a function may be associated to |
| 1486 | /// multiple different error sets, for example an inferred error set which | 1493 | /// 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 | }; |
| 1612 | 1627 | ||
| 1613 | pub const DeclAdapter = struct { | 1628 | pub 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`), or | 3021 | /// * 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 | } |
| 6871 | 6925 | ||
| 6926 | pub 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. |
| 6873 | pub fn errorSetFromUnsortedNames( | 6931 | pub 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; |
| 6453 | 6450 | ||
| ... | @@ -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; |
| 6457 | 6454 | ||
| 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 | |||
| 6480 | fn 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 | |||
| 6502 | fn 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 | }; |
| 6484 | 6533 | ||
| 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); |
| 6488 | 6537 | ||
| 6489 | const args_body = sema.code.extra[extra.end..]; | 6538 | const args_body = sema.code.extra[extra_end..]; |
| 6490 | 6539 | ||
| 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; |
| 6506 | 6555 | ||
| 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, |
| 6733 | 6782 | .async_kw => Air.Inst.Tag.call_async, | |
| 6734 | .async_kw => return sema.failWithUseOfAsync(block, call_src), | ||
| 6735 | }; | 6783 | }; |
| 6736 | 6784 | ||
| 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 | } |
| 7160 | 7208 | ||
| 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); | ||
| 7173 | 7223 | ||
| 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 | } |
| 7208 | 7258 | ||
| 7259 | fn 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 | |||
| 7281 | fn 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 | |||
| 7209 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { | 7309 | fn 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 | } |
| 7665 | 7765 | ||
| 7666 | try mod.ensureFuncBodyAnalysisQueued(callee_index); | 7766 | try mod.ensureFuncBodyAnalysisQueued(callee_index); |
| 7667 | 7767 | 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); | ||
| 7680 | 7771 | ||
| 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, |
| 33731 | 33823 | ||
| 33732 | .func_type => true, | 33824 | .func_type => true, |
| 33825 | .async_frame_type => false, | ||
| 33733 | 33826 | ||
| 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 above | 35369 | .simple_type, // handled above |
| 35276 | // values, not types | 35370 | // 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 | }, |
| 35935 | 36029 | ||
| 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()), |
| 35938 | 36033 | ||
| 35939 | // values, not types | 36034 | // 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=>strong | 1958 | /// `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 | }; |
| 2533 | 2541 | ||
| 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 | }; |
| 3103 | 3121 | ||
| 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), | ||
| 822 | 823 | ||
| 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 { |
| 4242 | 4243 | ||
| 4243 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 4244 | fn 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), | ||
| 806 | 807 | ||
| 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 { |
| 4215 | 4216 | ||
| 4216 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 4217 | fn 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), | ||
| 641 | 642 | ||
| 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 { |
| 1707 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 1708 | fn 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), | ||
| 654 | 655 | ||
| 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 { |
| 1293 | 1294 | ||
| 1294 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 1295 | fn 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}); | ||
| 1296 | 1298 | ||
| 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), | ||
| 1933 | 1934 | ||
| 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 { |
| 2180 | 2181 | ||
| 2181 | fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void { | 2182 | fn 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 values | 3131 | => unreachable, // types, not values |
| 3129 | 3132 | ||
| 3130 | .undef, .runtime_value => unreachable, // handled above | 3133 | .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), | ||
| 1904 | 1905 | ||
| 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 { |
| 8059 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 8060 | fn 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 values | 226 | => unreachable, // types, not values |
| 226 | 227 | ||
| 227 | .undef, .runtime_value => unreachable, // handled above | 228 | .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 values | 931 | // 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), | ||
| 3002 | 3004 | ||
| 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, |
| 3019 | 3019 | ||
| 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 | } |
| 3024 | 3048 | ||
| 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 values | 3199 | => unreachable, // types, not values |
| 3152 | 3200 | ||
| 3153 | .undef, .runtime_value => unreachable, // handled above | 3201 | .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), | ||
| 4477 | 4526 | ||
| 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 | } |
| 4941 | 4990 | ||
| 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 values | 646 | => unreachable, // types, not values |
| 646 | 647 | ||
| 647 | .undef, .runtime_value => unreachable, // handled above | 648 | .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), | ||
| 332 | 333 | ||
| 333 | .dbg_block_begin, .dbg_block_end => {}, | 334 | .dbg_block_begin, .dbg_block_end => {}, |
| 334 | 335 | ||
| ... | @@ -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 { |
| 362 | 362 | ||
| 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), | ||
| 365 | 366 | ||
| 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 | } |
| 838 | 839 | ||
| 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 | } |
| 1189 | 1190 | ||
| 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); | ||
| 1204 | 1208 | ||
| 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(", ["); |
| 1218 | 1244 | ||
| 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 | } |
| 1238 | 1264 | ||
| 1239 | try stream.writeAll("]) "); | 1265 | try stream.writeAll("]) "); |
| 1240 | try self.writeSrc(stream, inst_data.src()); | 1266 | try self.writeSrc(stream, src); |
| 1241 | } | 1267 | } |
| 1242 | 1268 | ||
| 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 | }, | ||
| 412 | 419 | ||
| 413 | // values, not types | 420 | // 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, |
| 510 | 518 | ||
| 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) }, |
| 1070 | 1079 | ||
| 1080 | // TODO: revisit this | ||
| 1081 | .async_frame_type => return AbiAlignmentAdvanced{ .scalar = 16 }, | ||
| 1082 | |||
| 1071 | // values, not types | 1083 | // 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 available | 1496 | .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) }, |
| 1486 | 1498 | ||
| 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 types | 1518 | // 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 | } |
| 1511 | 1542 | ||
| 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 | }, | ||
| 1720 | 1754 | ||
| 1721 | // values, not types | 1755 | // values, not types |
| 1722 | .undef, | 1756 | .undef, |
| ... | @@ -2263,6 +2297,7 @@ pub const Type = struct { | ... | @@ -2263,6 +2297,7 @@ pub const Type = struct { |
| 2263 | 2297 | ||
| 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, |
| 2267 | 2302 | ||
| 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, |
| 2449 | 2485 | ||
| 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 | }, |
| 2761 | 2797 | ||
| 2762 | .opaque_type => false, | 2798 | .opaque_type => false, |
| 2799 | .async_frame_type => false, | ||
| 2763 | 2800 | ||
| 2764 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), | 2801 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), |
| 2765 | 2802 |
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, | ||
| 352 | 353 | ||
| 353 | .undef, | 354 | .undef, |
| 354 | .runtime_value, | 355 | .runtime_value, |