zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit dfecf89d06dc2caad41ff54b05240506ea2c47e8 (tree)
parent 5d896a6cc6b7127dd4db0bd386ebe33da82d7824
Author: Robin Voetter <robin@voetter.nl>
Date:   Mon, 10 Apr 2023 18:34:30 +0200

spirv: fix OpFunctionCall parameters interleaving with insts

resolve() is now able to emit instructions. If usage of this function is
interleaved with calls to emitRaw() and writeOperand(), then an
instruction may get inserted between operands, causing an invalid module.
The solution here is to just perform a temporary allocation.

Diffstat:
Msrc/codegen/spirv.zig | 20+++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig @@ -2717,19 +2717,29 @@ pub const DeclGen = struct { const result_id = self.spv.allocId(); const callee_id = try self.resolve(pl_op.operand); - try self.func.body.emitRaw(self.spv.gpa, .OpFunctionCall, 3 + args.len); - self.func.body.writeOperand(spec.IdResultType, result_type_id); - self.func.body.writeOperand(spec.IdResult, result_id); - self.func.body.writeOperand(spec.IdRef, callee_id); + const params = try self.gpa.alloc(spec.IdRef, args.len); + defer self.gpa.free(params); + var n_params: usize = 0; for (args) |arg| { + // Note: resolve() might emit instructions, so we need to call it + // before starting to emit OpFunctionCall instructions. Hence the + // temporary params buffer. const arg_id = try self.resolve(arg); const arg_ty = self.air.typeOf(arg); if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; - self.func.body.writeOperand(spec.IdRef, arg_id); + params[n_params] = arg_id; + n_params += 1; } + try self.func.body.emit(self.spv.gpa, .OpFunctionCall, .{ + .id_result_type = result_type_id, + .id_result = result_id, + .function = callee_id, + .id_ref_3 = params[0..n_params], + }); + if (return_type.isNoReturn()) { try self.func.body.emit(self.spv.gpa, .OpUnreachable, {}); }