diff --git a/BRANCH_TODO b/BRANCH_TODO new file mode 100644 index 0000000000000000000000000000000000000000..95030f4966e292b661d23c51c82b90bac4746925 --- /dev/null +++ b/BRANCH_TODO @@ -0,0 +1,13 @@ + * detect when a called function is async and make the caller async too + * generate the async frame type *after* lowering the function to LLVM IR + * calculate frame size after llvm lowering, ability to inspect with `@sizeOf` + * spill only values that span across suspension points based on Liveness info + - handle variable lifetimes correctly - don't die until end curly brace + - don't pay for spill bytes that are not used - if an i32 spans across suspension point 1 + and a different value which is an f32 spans across suspension point 2, only 4 bytes + of spill data should be allocated. + - detect when first N spilled values are the same and avoid redundant stores + * solve safety panics for bad resume + * use function pointers instead of resume index to... + - reduce the number of runtime branches from 2 to 1 + - pass function arguments as normal arguments to the first segment diff --git a/src/Air.zig b/src/Air.zig index e08b94e56447e53022c83fd6df6e709875775673..5ae9959df462249173a29cb30c076894a235859c 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -318,6 +318,18 @@ pub const Inst = struct { /// This instruction also acts as an alloc. /// Uses `ty_pl` field with the `AsyncCallAlloc` payload. call_async_alloc, + /// Enter a suspend block. After this instruction, the function is + /// still executing but is considered to be in a "suspended" state, and + /// can be resumed, which will send control flow to just after the next + /// suspend_end instruction. + /// Result type is always void. + /// Uses the `no_op` field. + suspend_begin, + /// Exit a suspend block. This causes an async function to return + /// control flow to the resumer. + /// Result type is always void. + /// Uses the `no_op` field. + suspend_end, /// Count leading zeroes of an integer according to its representation in twos complement. /// Result type will always be an unsigned integer big enough to fit the answer. /// Uses the `ty_op` field. @@ -1440,6 +1452,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) .vector_store_elem, .c_va_end, .call_async, + .suspend_begin, + .suspend_end, => return Type.void, .int_from_ptr, @@ -1632,6 +1646,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .cmpxchg_weak, .cmpxchg_strong, .fence, + .suspend_begin, + .suspend_end, .atomic_store_unordered, .atomic_store_monotonic, .atomic_store_release, diff --git a/src/AstGen.zig b/src/AstGen.zig index d2caef1b95b8448b36c99b933dacebd10440f9a6..8c15bc85749137dca13ab201e43cc962fd158680 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1182,11 +1182,7 @@ fn nosuspendExpr( return expr(gz, scope, ri, body_node); } -fn suspendExpr( - gz: *GenZir, - scope: *Scope, - node: Ast.Node.Index, -) InnerError!Zir.Inst.Ref { +fn suspendExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; const tree = astgen.tree; @@ -2562,7 +2558,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .block, .block_comptime, .block_inline, - .suspend_block, .loop, .bool_br_and, .bool_br_or, @@ -2790,6 +2785,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .validate_deref, .save_err_ret_index, .restore_err_ret_index, + .suspend_block, => break :b true, .@"defer" => unreachable, diff --git a/src/Liveness.zig b/src/Liveness.zig index 6844f8216798e5a10fe12535c42fdb3911e90104..332ce4102de6dbe8e0fdeb447952a8a73daaa35b 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -344,7 +344,10 @@ pub fn categorizeOperand( .work_group_id, => return .none, - .fence => return .write, + .suspend_begin, + .suspend_end, + .fence, + => return .write, .not, .bitcast, @@ -1013,6 +1016,8 @@ fn analyzeInst( .dbg_block_begin, .dbg_block_end, .fence, + .suspend_begin, + .suspend_end, .ret_addr, .frame_addr, .wasm_memory_size, diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index 2d0d694761193721aa1d988900710fe4f64d9c9c..d5efe74b1091cc4780f7f419d85dcee56a3d6306 100644 --- a/src/Liveness/Verify.zig +++ b/src/Liveness/Verify.zig @@ -52,6 +52,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { .dbg_block_begin, .dbg_block_end, .fence, + .suspend_begin, + .suspend_end, .ret_addr, .frame_addr, .wasm_memory_size, diff --git a/src/Module.zig b/src/Module.zig index bd713a816409ace001ba06637ab967ecca002dde..22ccbf382b805241f22bdcbc70c9e64794e569e8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5742,6 +5742,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE sema.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)] = main_block_index; func.state = .success; + if (func.async_status == .unknown) { + func.async_status = .not_async; + } // Finally we must resolve the return type and parameter types so that backends // have full access to type information. diff --git a/src/Sema.zig b/src/Sema.zig index 9dce513b24ed99342836e9ba1b8040891af738ae..32eba6d500a5842e1226211d4ea112ab04f1a001 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -932,7 +932,6 @@ fn analyzeBodyInner( .bit_not => try sema.zirBitNot(block, inst), .bit_or => try sema.zirBitwise(block, inst, .bit_or), .bitcast => try sema.zirBitcast(block, inst), - .suspend_block => try sema.zirSuspendBlock(block, inst), .bool_not => try sema.zirBoolNot(block, inst), .bool_br_and => try sema.zirBoolBr(block, inst, false), .bool_br_or => try sema.zirBoolBr(block, inst, true), @@ -1218,6 +1217,11 @@ fn analyzeBodyInner( // continue the loop. // We also know that they cannot be referenced later, so we avoid // putting them into the map. + .suspend_block => { + try sema.zirSuspendBlock(block, inst); + i += 1; + continue; + }, .dbg_stmt => { try sema.zirDbgStmt(block, inst); i += 1; @@ -5594,10 +5598,16 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr return sema.addConstant(file_root_decl.val); } -fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); - return sema.failWithUseOfAsync(parent_block, src); +fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!void { + const pl_node = sema.code.instructions.items(.data)[inst].pl_node; + const src = pl_node.src(); + const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); + const body = sema.code.extra[extra.end..][0..extra.data.body_len]; + _ = src; + sema.owner_func.?.async_status = .yes_async; + _ = try parent_block.addNoOp(.suspend_begin); + _ = try sema.resolveBody(parent_block, body, inst); + _ = try parent_block.addNoOp(.suspend_end); } fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Air.Inst.Ref { diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index d5d5c3ec18a07be0a6e171a65ad34d3333856165..93f734da141e9395a8aa285486fe779790966807 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -822,6 +822,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .call_async => try self.airCall(inst, .async_kw), .call_async_alloc => try self.airCall(inst, .async_kw), + .suspend_begin => try airSuspendBegin(self, inst), + .suspend_end => try airSuspendEnd (self, inst), + .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), .atomic_store_release => try self.airAtomicStore(inst, .Release), @@ -4242,6 +4245,16 @@ fn airFence(self: *Self) !void { //return self.finishAirBookkeeping(); } +fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_begin for aarch64", .{}); +} + +fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_end for aarch64", .{}); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{}); if (modifier == .async_kw) return self.fail("TODO implement async calls for aarch64", .{}); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index d845be6afbfb60a7881eda577b57dbe9a1e58b11..d8e48ba7dcb6b58b825f3908d1897656c2f65656 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -806,6 +806,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .call_async => try self.airCall(inst, .async_kw), .call_async_alloc => try self.airCall(inst, .async_kw), + .suspend_begin => try airSuspendBegin(self, inst), + .suspend_end => try airSuspendEnd (self, inst), + .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), .atomic_store_release => try self.airAtomicStore(inst, .Release), @@ -4215,6 +4218,16 @@ fn airFence(self: *Self) !void { //return self.finishAirBookkeeping(); } +fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_begin for arm", .{}); +} + +fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_end for arm", .{}); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{}); if (modifier == .async_kw) return self.fail("TODO implement async calls for arm", .{}); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 80858e6ce4676c4a637337627b81d0205299138b..959f4c35e69f90f3e913e38759677760e929827c 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -641,6 +641,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .call_async => try self.airCall(inst, .async_kw), .call_async_alloc => try self.airCall(inst, .async_kw), + .suspend_begin => try airSuspendBegin(self, inst), + .suspend_end => try airSuspendEnd (self, inst), + .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), .atomic_store_release => try self.airAtomicStore(inst, .Release), @@ -1706,6 +1709,16 @@ fn airFence(self: *Self) !void { //return self.finishAirBookkeeping(); } +fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_begin for riscv64", .{}); +} + +fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_end for riscv64", .{}); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { const mod = self.bin_file.options.module.?; if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index f30c128b2bdda51f4c4046f27f975d155b8add69..0a8764abe0c195609d6e9606798f100a17f71e7a 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -654,6 +654,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .call_async => try self.airCall(inst, .async_kw), .call_async_alloc => try self.airCall(inst, .async_kw), + .suspend_begin => try airSuspendBegin(self, inst), + .suspend_end => try airSuspendEnd (self, inst), + .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"), .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"), .atomic_store_release => @panic("TODO try self.airAtomicStore(inst, .Release)"), @@ -1293,6 +1296,16 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_begin for sparc64", .{}); +} + +fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_end for sparc64", .{}); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch}); if (modifier == .async_kw) return self.fail("TODO implement async calls for {}", .{self.target.cpu.arch}); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 92f1be615870dec177bef110ca5c5d764dd77f82..49c84d256ac1d20b46913b038e164379816c4236 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1933,6 +1933,9 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .call_async => func.airCall(inst, .async_kw), .call_async_alloc => func.airCall(inst, .async_kw), + .suspend_begin => func.airSuspendBegin(inst), + .suspend_end => func.airSuspendEnd(inst), + .is_err => func.airIsErr(inst, .i32_ne), .is_non_err => func.airIsErr(inst, .i32_eq), @@ -2180,6 +2183,16 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.finishAir(inst, .none, &.{un_op}); } +fn airSuspendBegin(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + _ = inst; + return func.fail("TODO implement suspend_begin for wasm", .{}); +} + +fn airSuspendEnd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + _ = inst; + return func.fail("TODO implement suspend_end for wasm", .{}); +} + fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void { if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{}); if (modifier == .async_kw) return func.fail("TODO implement async calls for wasm", .{}); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index f373b5708020799bb0c5a812cb762bc378068fc8..6576eb312df4769509d731f7a87f29b2dc68f8ab 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1904,6 +1904,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .call_async => try self.airCall(inst, .async_kw), .call_async_alloc => try self.airCall(inst, .async_kw), + .suspend_begin => try airSuspendBegin(self, inst), + .suspend_end => try airSuspendEnd (self, inst), + .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), .atomic_store_release => try self.airAtomicStore(inst, .Release), @@ -8058,6 +8061,16 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { return self.finishAirBookkeeping(); } +fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_begin for x86_64", .{}); +} + +fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void { + _ = inst; + return self.fail("TODO implement suspend_end for x86_64", .{}); +} + fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { const mod = self.bin_file.options.module.?; if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 968d567121a023e5268b9d5e9bad6cbc38835a11..c92c1e8135239c99db28110eebad9711c7cfa7da 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3003,6 +3003,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .call_async => try airCall(f, inst, .async_kw), .call_async_alloc => try airCall(f, inst, .async_kw), + .suspend_begin => try airSuspendBegin(f, inst), + .suspend_end => try airSuspendEnd (f, inst), + .float_from_int, .int_from_float, .fptrunc, @@ -4087,6 +4090,16 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { return local; } +fn airSuspendBegin(f: *Function, inst: Air.Inst.Index) !CValue { + _ = inst; + return f.fail("TODO: C backend: lower suspend_begin", .{}); +} + +fn airSuspendEnd(f: *Function, inst: Air.Inst.Index) !CValue { + _ = inst; + return f.fail("TODO: C backend: lower suspend_end", .{}); +} + fn airCall( f: *Function, inst: Air.Inst.Index, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c967e0572f997bc1d94178f65fda8643d6e7c99a..46bf7349c89d649dc50131517930d7b1c916f2d0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1207,9 +1207,35 @@ pub const Object = struct { .prev_dbg_line = 0, .prev_dbg_column = 0, .err_ret_trace = err_ret_trace, + + .resume_block_index = 0, + .resume_bb = undefined, + .async_switch = undefined, + .resume_index_ptr = undefined, }; defer fg.deinit(); + if (func.isAsync()) { + const frame_ty = try mod.asyncFrameType(func_index); + const frame_size = frame_ty.abiSize(mod); + const llvm_usize = dg.context.intType(target.ptrBitWidth()); + const size_val = llvm_usize.constInt(frame_size, .False); + llvm_func.functionSetPrefixData(size_val); + + const async_preamble_bb = dg.context.appendBasicBlock(llvm_func, "AsyncSwitch"); + const bad_resume_bb = dg.context.appendBasicBlock(llvm_func, "BadResume"); + builder.positionBuilderAtEnd(bad_resume_bb); + _ = builder.buildUnreachable(); // TODO make this a safety panic + + builder.positionBuilderAtEnd(async_preamble_bb); + const l = asyncFrameLayout(); + const frame_llvm_ty = try dg.lowerType(frame_ty); + const frame_ptr = llvm_func.getParam(0); + fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, ""); + const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, ""); + fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4); + } + fg.genBody(air.getMainBody()) catch |err| switch (err) { error.CodegenFail => { decl.analysis = .codegen_failure; @@ -4308,6 +4334,12 @@ pub const FuncGen = struct { prev_dbg_line: c_uint, prev_dbg_column: c_uint, + // async stuff + resume_block_index: u32, + resume_bb: *llvm.BasicBlock, + async_switch: *llvm.Value, + resume_index_ptr: *llvm.Value, + /// Stack of locations where a call was inlined. dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{}, @@ -4549,8 +4581,11 @@ pub const FuncGen = struct { .call_always_tail => try self.airCall(inst, .AlwaysTail), .call_never_tail => try self.airCall(inst, .NeverTail), .call_never_inline => try self.airCall(inst, .NeverInline), - .call_async_alloc => try self.airCallAsyncAlloc(inst), - .call_async => try self.airCallAsync(inst), + + .call_async_alloc => try self.airCallAsyncAlloc(inst), + .call_async => try self.airCallAsync(inst), + .suspend_begin => try self.airSuspendBegin(), + .suspend_end => try self.airSuspendEnd(), .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), @@ -4819,9 +4854,37 @@ pub const FuncGen = struct { } } - fn airCallAsync(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + fn airSuspendBegin(fg: *FuncGen) !?*llvm.Value { + fg.resume_bb = genSuspendBegin(fg, "SuspendResume"); + return null; + } + + fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock { + const target = fg.getTarget(); + const llvm_usize = fg.dg.context.intType(target.ptrBitWidth()); + const resume_bb = fg.context.appendBasicBlock(fg.llvm_func, name_hint); + const new_block_index = fg.resume_block_index; + fg.resume_block_index += 1; + const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False); + fg.async_switch.addCase(new_block_index_llvm_val, resume_bb); + _ = fg.builder.buildStore(new_block_index_llvm_val, fg.resume_index_ptr); + return resume_bb; + } + + fn airSuspendEnd(fg: *FuncGen) !?*llvm.Value { + _ = fg.builder.buildRetVoid(); + fg.builder.positionBuilderAtEnd(fg.resume_bb); + fg.resume_bb = undefined; + + // TODO safety, store the index of the "not suspended" panic basic + // block into resume_index_ptr + + return null; + } + + fn airCallAsync(fg: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { _ = inst; - return self.todo("lower call_async", .{}); + return fg.todo("lower call_async", .{}); } fn airCallAsyncAlloc(fg: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 2ac0851050be2483c456a8e5a6c973c68a66d035..a73fa87b987ac78ca488e1316bf8e7bbbfb7ab4f 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -259,6 +259,9 @@ pub const Value = opaque { pub const attachMetaData = ZigLLVMAttachMetaData; extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void; + + pub const functionSetPrefixData = ZigLLVMFunctionSetPrefixData; + extern fn ZigLLVMFunctionSetPrefixData(func: *Value, data: *Value) void; }; pub const Type = opaque { diff --git a/src/print_air.zig b/src/print_air.zig index 6064da44412cf934c2db8d37fb82c8cba6a551b4..da6f5d0b28edfb33d58a2e1fa0891a2583d14e75 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -217,6 +217,8 @@ const Writer = struct { .ret_addr, .frame_addr, .save_err_return_trace_index, + .suspend_begin, + .suspend_end, => try w.writeNoOp(s, inst), .alloc,