authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-21 20:12:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-26 15:57:07-07:00
loge45b10f3d453f3bd8326631ee786a2ef247e8953
tree92a8b593bbb1d06f696ce57826fc74438dfc1b1d
parentf1b7c76ae9c015eeadeeff6ffcdf1523afce43f5

stage2: implement suspend blocks

* AstGen: suspend blocks are always void * add new AIR instructions: suspend_begin and suspend_end * Module: after a function's body is analyzed, conclude that it is not async if it wasn't proven async during analysis. * LLVM: implement lowering of suspend_begin and suspend_end. There is a lot to do in this branch. I started a branch-local TODO list in the BRANCH_TODO file. All of these tasks should be finished before merging into master.

17 files changed, 220 insertions(+), 16 deletions(-)

BRANCH_TODO created+13
......@@ -0,0 +1,13 @@
1 * detect when a called function is async and make the caller async too
2 * generate the async frame type *after* lowering the function to LLVM IR
3 * calculate frame size after llvm lowering, ability to inspect with `@sizeOf`
4 * spill only values that span across suspension points based on Liveness info
5 - handle variable lifetimes correctly - don't die until end curly brace
6 - don't pay for spill bytes that are not used - if an i32 spans across suspension point 1
7 and a different value which is an f32 spans across suspension point 2, only 4 bytes
8 of spill data should be allocated.
9 - detect when first N spilled values are the same and avoid redundant stores
10 * solve safety panics for bad resume
11 * use function pointers instead of resume index to...
12 - reduce the number of runtime branches from 2 to 1
13 - pass function arguments as normal arguments to the first segment
src/Air.zig+16
......@@ -318,6 +318,18 @@ pub const Inst = struct {
318318 /// This instruction also acts as an alloc.
319319 /// Uses `ty_pl` field with the `AsyncCallAlloc` payload.
320320 call_async_alloc,
321 /// Enter a suspend block. After this instruction, the function is
322 /// still executing but is considered to be in a "suspended" state, and
323 /// can be resumed, which will send control flow to just after the next
324 /// suspend_end instruction.
325 /// Result type is always void.
326 /// Uses the `no_op` field.
327 suspend_begin,
328 /// Exit a suspend block. This causes an async function to return
329 /// control flow to the resumer.
330 /// Result type is always void.
331 /// Uses the `no_op` field.
332 suspend_end,
321333 /// Count leading zeroes of an integer according to its representation in twos complement.
322334 /// Result type will always be an unsigned integer big enough to fit the answer.
323335 /// Uses the `ty_op` field.
......@@ -1440,6 +1452,8 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
14401452 .vector_store_elem,
14411453 .c_va_end,
14421454 .call_async,
1455 .suspend_begin,
1456 .suspend_end,
14431457 => return Type.void,
14441458
14451459 .int_from_ptr,
......@@ -1632,6 +1646,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
16321646 .cmpxchg_weak,
16331647 .cmpxchg_strong,
16341648 .fence,
1649 .suspend_begin,
1650 .suspend_end,
16351651 .atomic_store_unordered,
16361652 .atomic_store_monotonic,
16371653 .atomic_store_release,
src/AstGen.zig+2-6
......@@ -1182,11 +1182,7 @@ fn nosuspendExpr(
11821182 return expr(gz, scope, ri, body_node);
11831183}
11841184
1185fn suspendExpr(
1186 gz: *GenZir,
1187 scope: *Scope,
1188 node: Ast.Node.Index,
1189) InnerError!Zir.Inst.Ref {
1185fn suspendExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
11901186 const astgen = gz.astgen;
11911187 const gpa = astgen.gpa;
11921188 const tree = astgen.tree;
......@@ -2562,7 +2558,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25622558 .block,
25632559 .block_comptime,
25642560 .block_inline,
2565 .suspend_block,
25662561 .loop,
25672562 .bool_br_and,
25682563 .bool_br_or,
......@@ -2790,6 +2785,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27902785 .validate_deref,
27912786 .save_err_ret_index,
27922787 .restore_err_ret_index,
2788 .suspend_block,
27932789 => break :b true,
27942790
27952791 .@"defer" => unreachable,
src/Liveness.zig+6-1
......@@ -344,7 +344,10 @@ pub fn categorizeOperand(
344344 .work_group_id,
345345 => return .none,
346346
347 .fence => return .write,
347 .suspend_begin,
348 .suspend_end,
349 .fence,
350 => return .write,
348351
349352 .not,
350353 .bitcast,
......@@ -1013,6 +1016,8 @@ fn analyzeInst(
10131016 .dbg_block_begin,
10141017 .dbg_block_end,
10151018 .fence,
1019 .suspend_begin,
1020 .suspend_end,
10161021 .ret_addr,
10171022 .frame_addr,
10181023 .wasm_memory_size,
src/Liveness/Verify.zig+2
......@@ -52,6 +52,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
5252 .dbg_block_begin,
5353 .dbg_block_end,
5454 .fence,
55 .suspend_begin,
56 .suspend_end,
5557 .ret_addr,
5658 .frame_addr,
5759 .wasm_memory_size,
src/Module.zig+3
......@@ -5742,6 +5742,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
57425742 sema.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)] = main_block_index;
57435743
57445744 func.state = .success;
5745 if (func.async_status == .unknown) {
5746 func.async_status = .not_async;
5747 }
57455748
57465749 // Finally we must resolve the return type and parameter types so that backends
57475750 // have full access to type information.
src/Sema.zig+15-5
......@@ -932,7 +932,6 @@ fn analyzeBodyInner(
932932 .bit_not => try sema.zirBitNot(block, inst),
933933 .bit_or => try sema.zirBitwise(block, inst, .bit_or),
934934 .bitcast => try sema.zirBitcast(block, inst),
935 .suspend_block => try sema.zirSuspendBlock(block, inst),
936935 .bool_not => try sema.zirBoolNot(block, inst),
937936 .bool_br_and => try sema.zirBoolBr(block, inst, false),
938937 .bool_br_or => try sema.zirBoolBr(block, inst, true),
......@@ -1218,6 +1217,11 @@ fn analyzeBodyInner(
12181217 // continue the loop.
12191218 // We also know that they cannot be referenced later, so we avoid
12201219 // putting them into the map.
1220 .suspend_block => {
1221 try sema.zirSuspendBlock(block, inst);
1222 i += 1;
1223 continue;
1224 },
12211225 .dbg_stmt => {
12221226 try sema.zirDbgStmt(block, inst);
12231227 i += 1;
......@@ -5594,10 +5598,16 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
55945598 return sema.addConstant(file_root_decl.val);
55955599}
55965600
5597fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5598 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5599 const src = inst_data.src();
5600 return sema.failWithUseOfAsync(parent_block, src);
5601fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!void {
5602 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
5603 const src = pl_node.src();
5604 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
5605 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
5606 _ = src;
5607 sema.owner_func.?.async_status = .yes_async;
5608 _ = try parent_block.addNoOp(.suspend_begin);
5609 _ = try sema.resolveBody(parent_block, body, inst);
5610 _ = try parent_block.addNoOp(.suspend_end);
56015611}
56025612
56035613fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Air.Inst.Ref {
src/arch/aarch64/CodeGen.zig+13
......@@ -822,6 +822,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
822822 .call_async => try self.airCall(inst, .async_kw),
823823 .call_async_alloc => try self.airCall(inst, .async_kw),
824824
825 .suspend_begin => try airSuspendBegin(self, inst),
826 .suspend_end => try airSuspendEnd (self, inst),
827
825828 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
826829 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
827830 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -4242,6 +4245,16 @@ fn airFence(self: *Self) !void {
42424245 //return self.finishAirBookkeeping();
42434246}
42444247
4248fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void {
4249 _ = inst;
4250 return self.fail("TODO implement suspend_begin for aarch64", .{});
4251}
4252
4253fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void {
4254 _ = inst;
4255 return self.fail("TODO implement suspend_end for aarch64", .{});
4256}
4257
42454258fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
42464259 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});
42474260 if (modifier == .async_kw) return self.fail("TODO implement async calls for aarch64", .{});
src/arch/arm/CodeGen.zig+13
......@@ -806,6 +806,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
806806 .call_async => try self.airCall(inst, .async_kw),
807807 .call_async_alloc => try self.airCall(inst, .async_kw),
808808
809 .suspend_begin => try airSuspendBegin(self, inst),
810 .suspend_end => try airSuspendEnd (self, inst),
811
809812 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
810813 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
811814 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -4215,6 +4218,16 @@ fn airFence(self: *Self) !void {
42154218 //return self.finishAirBookkeeping();
42164219}
42174220
4221fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void {
4222 _ = inst;
4223 return self.fail("TODO implement suspend_begin for arm", .{});
4224}
4225
4226fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void {
4227 _ = inst;
4228 return self.fail("TODO implement suspend_end for arm", .{});
4229}
4230
42184231fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
42194232 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});
42204233 if (modifier == .async_kw) return self.fail("TODO implement async calls for arm", .{});
src/arch/riscv64/CodeGen.zig+13
......@@ -641,6 +641,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
641641 .call_async => try self.airCall(inst, .async_kw),
642642 .call_async_alloc => try self.airCall(inst, .async_kw),
643643
644 .suspend_begin => try airSuspendBegin(self, inst),
645 .suspend_end => try airSuspendEnd (self, inst),
646
644647 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
645648 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
646649 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -1706,6 +1709,16 @@ fn airFence(self: *Self) !void {
17061709 //return self.finishAirBookkeeping();
17071710}
17081711
1712fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void {
1713 _ = inst;
1714 return self.fail("TODO implement suspend_begin for riscv64", .{});
1715}
1716
1717fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void {
1718 _ = inst;
1719 return self.fail("TODO implement suspend_end for riscv64", .{});
1720}
1721
17091722fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
17101723 const mod = self.bin_file.options.module.?;
17111724 if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{});
src/arch/sparc64/CodeGen.zig+13
......@@ -654,6 +654,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
654654 .call_async => try self.airCall(inst, .async_kw),
655655 .call_async_alloc => try self.airCall(inst, .async_kw),
656656
657 .suspend_begin => try airSuspendBegin(self, inst),
658 .suspend_end => try airSuspendEnd (self, inst),
659
657660 .atomic_store_unordered => @panic("TODO try self.airAtomicStore(inst, .Unordered)"),
658661 .atomic_store_monotonic => @panic("TODO try self.airAtomicStore(inst, .Monotonic)"),
659662 .atomic_store_release => @panic("TODO try self.airAtomicStore(inst, .Release)"),
......@@ -1293,6 +1296,16 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void {
12931296 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12941297}
12951298
1299fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void {
1300 _ = inst;
1301 return self.fail("TODO implement suspend_begin for sparc64", .{});
1302}
1303
1304fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void {
1305 _ = inst;
1306 return self.fail("TODO implement suspend_end for sparc64", .{});
1307}
1308
12961309fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
12971310 if (modifier == .always_tail) return self.fail("TODO implement tail calls for {}", .{self.target.cpu.arch});
12981311 if (modifier == .async_kw) return self.fail("TODO implement async calls for {}", .{self.target.cpu.arch});
src/arch/wasm/CodeGen.zig+13
......@@ -1933,6 +1933,9 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19331933 .call_async => func.airCall(inst, .async_kw),
19341934 .call_async_alloc => func.airCall(inst, .async_kw),
19351935
1936 .suspend_begin => func.airSuspendBegin(inst),
1937 .suspend_end => func.airSuspendEnd(inst),
1938
19361939 .is_err => func.airIsErr(inst, .i32_ne),
19371940 .is_non_err => func.airIsErr(inst, .i32_eq),
19381941
......@@ -2180,6 +2183,16 @@ fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21802183 return func.finishAir(inst, .none, &.{un_op});
21812184}
21822185
2186fn airSuspendBegin(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2187 _ = inst;
2188 return func.fail("TODO implement suspend_begin for wasm", .{});
2189}
2190
2191fn airSuspendEnd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2192 _ = inst;
2193 return func.fail("TODO implement suspend_end for wasm", .{});
2194}
2195
21832196fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void {
21842197 if (modifier == .always_tail) return func.fail("TODO implement tail calls for wasm", .{});
21852198 if (modifier == .async_kw) return func.fail("TODO implement async calls for wasm", .{});
src/arch/x86_64/CodeGen.zig+13
......@@ -1904,6 +1904,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
19041904 .call_async => try self.airCall(inst, .async_kw),
19051905 .call_async_alloc => try self.airCall(inst, .async_kw),
19061906
1907 .suspend_begin => try airSuspendBegin(self, inst),
1908 .suspend_end => try airSuspendEnd (self, inst),
1909
19071910 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
19081911 .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
19091912 .atomic_store_release => try self.airAtomicStore(inst, .Release),
......@@ -8058,6 +8061,16 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void {
80588061 return self.finishAirBookkeeping();
80598062}
80608063
8064fn airSuspendBegin(self: *Self, inst: Air.Inst.Index) !void {
8065 _ = inst;
8066 return self.fail("TODO implement suspend_begin for x86_64", .{});
8067}
8068
8069fn airSuspendEnd(self: *Self, inst: Air.Inst.Index) !void {
8070 _ = inst;
8071 return self.fail("TODO implement suspend_end for x86_64", .{});
8072}
8073
80618074fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
80628075 const mod = self.bin_file.options.module.?;
80638076 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
src/codegen/c.zig+13
......@@ -3003,6 +3003,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
30033003 .call_async => try airCall(f, inst, .async_kw),
30043004 .call_async_alloc => try airCall(f, inst, .async_kw),
30053005
3006 .suspend_begin => try airSuspendBegin(f, inst),
3007 .suspend_end => try airSuspendEnd (f, inst),
3008
30063009 .float_from_int,
30073010 .int_from_float,
30083011 .fptrunc,
......@@ -4087,6 +4090,16 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
40874090 return local;
40884091}
40894092
4093fn airSuspendBegin(f: *Function, inst: Air.Inst.Index) !CValue {
4094 _ = inst;
4095 return f.fail("TODO: C backend: lower suspend_begin", .{});
4096}
4097
4098fn airSuspendEnd(f: *Function, inst: Air.Inst.Index) !CValue {
4099 _ = inst;
4100 return f.fail("TODO: C backend: lower suspend_end", .{});
4101}
4102
40904103fn airCall(
40914104 f: *Function,
40924105 inst: Air.Inst.Index,
src/codegen/llvm.zig+67-4
......@@ -1207,9 +1207,35 @@ pub const Object = struct {
12071207 .prev_dbg_line = 0,
12081208 .prev_dbg_column = 0,
12091209 .err_ret_trace = err_ret_trace,
1210
1211 .resume_block_index = 0,
1212 .resume_bb = undefined,
1213 .async_switch = undefined,
1214 .resume_index_ptr = undefined,
12101215 };
12111216 defer fg.deinit();
12121217
1218 if (func.isAsync()) {
1219 const frame_ty = try mod.asyncFrameType(func_index);
1220 const frame_size = frame_ty.abiSize(mod);
1221 const llvm_usize = dg.context.intType(target.ptrBitWidth());
1222 const size_val = llvm_usize.constInt(frame_size, .False);
1223 llvm_func.functionSetPrefixData(size_val);
1224
1225 const async_preamble_bb = dg.context.appendBasicBlock(llvm_func, "AsyncSwitch");
1226 const bad_resume_bb = dg.context.appendBasicBlock(llvm_func, "BadResume");
1227 builder.positionBuilderAtEnd(bad_resume_bb);
1228 _ = builder.buildUnreachable(); // TODO make this a safety panic
1229
1230 builder.positionBuilderAtEnd(async_preamble_bb);
1231 const l = asyncFrameLayout();
1232 const frame_llvm_ty = try dg.lowerType(frame_ty);
1233 const frame_ptr = llvm_func.getParam(0);
1234 fg.resume_index_ptr = builder.buildStructGEP(frame_llvm_ty, frame_ptr, l.resume_index, "");
1235 const resume_index = builder.buildLoad(llvm_usize, fg.resume_index_ptr, "");
1236 fg.async_switch = builder.buildSwitch(resume_index, bad_resume_bb, 4);
1237 }
1238
12131239 fg.genBody(air.getMainBody()) catch |err| switch (err) {
12141240 error.CodegenFail => {
12151241 decl.analysis = .codegen_failure;
......@@ -4308,6 +4334,12 @@ pub const FuncGen = struct {
43084334 prev_dbg_line: c_uint,
43094335 prev_dbg_column: c_uint,
43104336
4337 // async stuff
4338 resume_block_index: u32,
4339 resume_bb: *llvm.BasicBlock,
4340 async_switch: *llvm.Value,
4341 resume_index_ptr: *llvm.Value,
4342
43114343 /// Stack of locations where a call was inlined.
43124344 dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
43134345
......@@ -4549,8 +4581,11 @@ pub const FuncGen = struct {
45494581 .call_always_tail => try self.airCall(inst, .AlwaysTail),
45504582 .call_never_tail => try self.airCall(inst, .NeverTail),
45514583 .call_never_inline => try self.airCall(inst, .NeverInline),
4552 .call_async_alloc => try self.airCallAsyncAlloc(inst),
4553 .call_async => try self.airCallAsync(inst),
4584
4585 .call_async_alloc => try self.airCallAsyncAlloc(inst),
4586 .call_async => try self.airCallAsync(inst),
4587 .suspend_begin => try self.airSuspendBegin(),
4588 .suspend_end => try self.airSuspendEnd(),
45544589
45554590 .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
45564591 .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
......@@ -4819,9 +4854,37 @@ pub const FuncGen = struct {
48194854 }
48204855 }
48214856
4822 fn airCallAsync(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
4857 fn airSuspendBegin(fg: *FuncGen) !?*llvm.Value {
4858 fg.resume_bb = genSuspendBegin(fg, "SuspendResume");
4859 return null;
4860 }
4861
4862 fn genSuspendBegin(fg: *FuncGen, name_hint: [*:0]const u8) *llvm.BasicBlock {
4863 const target = fg.getTarget();
4864 const llvm_usize = fg.dg.context.intType(target.ptrBitWidth());
4865 const resume_bb = fg.context.appendBasicBlock(fg.llvm_func, name_hint);
4866 const new_block_index = fg.resume_block_index;
4867 fg.resume_block_index += 1;
4868 const new_block_index_llvm_val = llvm_usize.constInt(new_block_index, .False);
4869 fg.async_switch.addCase(new_block_index_llvm_val, resume_bb);
4870 _ = fg.builder.buildStore(new_block_index_llvm_val, fg.resume_index_ptr);
4871 return resume_bb;
4872 }
4873
4874 fn airSuspendEnd(fg: *FuncGen) !?*llvm.Value {
4875 _ = fg.builder.buildRetVoid();
4876 fg.builder.positionBuilderAtEnd(fg.resume_bb);
4877 fg.resume_bb = undefined;
4878
4879 // TODO safety, store the index of the "not suspended" panic basic
4880 // block into resume_index_ptr
4881
4882 return null;
4883 }
4884
4885 fn airCallAsync(fg: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
48234886 _ = inst;
4824 return self.todo("lower call_async", .{});
4887 return fg.todo("lower call_async", .{});
48254888 }
48264889
48274890 fn airCallAsyncAlloc(fg: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
src/codegen/llvm/bindings.zig+3
......@@ -259,6 +259,9 @@ pub const Value = opaque {
259259
260260 pub const attachMetaData = ZigLLVMAttachMetaData;
261261 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
262
263 pub const functionSetPrefixData = ZigLLVMFunctionSetPrefixData;
264 extern fn ZigLLVMFunctionSetPrefixData(func: *Value, data: *Value) void;
262265};
263266
264267pub const Type = opaque {
src/print_air.zig+2
......@@ -217,6 +217,8 @@ const Writer = struct {
217217 .ret_addr,
218218 .frame_addr,
219219 .save_err_return_trace_index,
220 .suspend_begin,
221 .suspend_end,
220222 => try w.writeNoOp(s, inst),
221223
222224 .alloc,