authorgravatar for vasyapulopapik@gmail.comKleshzz <vasyapulopapik@gmail.com> 2026-07-23 15:05:18+03:00
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-07-26 21:07:52+02:00
log2aa8f3d3f5bf98d1a6a7396c608e24203cf094be
treef2d2715b792c1822129c09ad3480df48cea0d1f3
parentd552433946de375430a339e245b5ea0af1b79ca6

spirv: improve assembler capacity allocation, error locations


1 files changed, 22 insertions(+), 20 deletions(-)

src/codegen/spirv/Assembler.zig+22-20
...@@ -26,7 +26,7 @@ inst: struct {...@@ -26,7 +26,7 @@ inst: struct {
26 string_bytes: std.ArrayList(u8) = .empty,26 string_bytes: std.ArrayList(u8) = .empty,
27 inst_offset: u32 = 0,27 inst_offset: u32 = 0,
2828
29 fn result(ass: @This()) ?AsmValue.Ref {29 fn result(ass: *const @This()) ?AsmValue.Ref {
30 for (ass.operands.items[0..@min(ass.operands.items.len, 2)]) |op| {30 for (ass.operands.items[0..@min(ass.operands.items.len, 2)]) |op| {
31 switch (op) {31 switch (op) {
32 .result_id => |index| return index,32 .result_id => |index| return index,
...@@ -179,19 +179,19 @@ fn processInstruction(ass: *Assembler) !void {...@@ -179,19 +179,19 @@ fn processInstruction(ass: *Assembler) !void {
179 const cg = ass.cg;179 const cg = ass.cg;
180 const result: AsmValue = switch (ass.inst.opcode) {180 const result: AsmValue = switch (ass.inst.opcode) {
181 .OpEntryPoint => {181 .OpEntryPoint => {
182 return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{});182 return ass.fail(ass.inst.inst_offset, "cannot export entry points in assembly", .{});
183 },183 },
184 .OpExecutionMode, .OpExecutionModeId => {184 .OpExecutionMode, .OpExecutionModeId => {
185 return ass.fail(ass.currentToken().start, "cannot set execution mode in assembly", .{});185 return ass.fail(ass.inst.inst_offset, "cannot set execution mode in assembly", .{});
186 },186 },
187 .OpCapability, .OpExtension => {187 .OpCapability, .OpExtension => {
188 return ass.fail(ass.currentToken().start, "cannot declare capabilities or extensions in assembly; use -mcpu instead", .{});188 return ass.fail(ass.inst.inst_offset, "cannot declare capabilities or extensions in assembly; use -mcpu instead", .{});
189 },189 },
190 .OpExtInstImport => blk: {190 .OpExtInstImport => blk: {
191 const set_name_offset = ass.inst.operands.items[1].string;191 const set_name_offset = ass.inst.operands.items[1].string;
192 const set_name = std.mem.sliceTo(ass.inst.string_bytes.items[set_name_offset..], 0);192 const set_name = std.mem.sliceTo(ass.inst.string_bytes.items[set_name_offset..], 0);
193 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {193 const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse {
194 return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name});194 return ass.fail(ass.inst.inst_offset, "unknown instruction set: {s}", .{set_name});
195 };195 };
196 break :blk .{ .value = try cg.importInstructionSet(set_tag) };196 break :blk .{ .value = try cg.importInstructionSet(set_tag) };
197 },197 },
...@@ -366,38 +366,40 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {...@@ -366,38 +366,40 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue {
366366
367 var maybe_result_id: ?Id = null;367 var maybe_result_id: ?Id = null;
368 const first_word = section.instructions.items.len;368 const first_word = section.instructions.items.len;
369 // At this point we're not quite sure how many operands this instruction is369
370 // going to have, so insert 0 and patch up the actual opcode word later.370 // Pre-calculate exact instruction size to avoid per-operand capacity checks.
371 try section.ensureUnusedCapacity(cg.gpa, 1);371 var total_words: usize = 1; // 1 word for the opcode itself
372 for (operands) |operand| {
373 total_words += switch (operand) {
374 .value, .literal32, .result_id, .ref_id => 1,
375 .literal64 => 2,
376 .string => |offset| blk: {
377 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);
378 break :blk @divCeil(text.len + 1, @sizeOf(Word));
379 },
380 };
381 }
382
383 try section.ensureUnusedCapacity(cg.gpa, total_words);
372 section.writeWord(0);384 section.writeWord(0);
373385
374 for (operands) |operand| {386 for (operands) |operand| {
375 switch (operand) {387 switch (operand) {
376 .value, .literal32 => |word| {388 .value, .literal32 => |word| section.writeWord(word),
377 try section.ensureUnusedCapacity(cg.gpa, 1);389 .literal64 => |dword| section.writeDoubleWord(dword),
378 section.writeWord(word);
379 },
380 .literal64 => |dword| {
381 try section.ensureUnusedCapacity(cg.gpa, 2);
382 section.writeDoubleWord(dword);
383 },
384 .result_id => {390 .result_id => {
385 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|391 maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index|
386 cg.declPtr(spv_decl_index).result_id392 cg.declPtr(spv_decl_index).result_id
387 else393 else
388 cg.allocId();394 cg.allocId();
389 try section.ensureUnusedCapacity(cg.gpa, 1);
390 section.writeOperand(Id, maybe_result_id.?);395 section.writeOperand(Id, maybe_result_id.?);
391 },396 },
392 .ref_id => |index| {397 .ref_id => |index| {
393 const result = try ass.resolveRef(index);398 const result = try ass.resolveRef(index);
394 try section.ensureUnusedCapacity(cg.gpa, 1);
395 section.writeOperand(spec.Id, result.resultId());399 section.writeOperand(spec.Id, result.resultId());
396 },400 },
397 .string => |offset| {401 .string => |offset| {
398 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);402 const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0);
399 const size = @divCeil(text.len + 1, @sizeOf(Word));
400 try section.ensureUnusedCapacity(cg.gpa, size);
401 section.writeOperand(spec.LiteralString, text);403 section.writeOperand(spec.LiteralString, text);
402 },404 },
403 }405 }