authorgravatar for vasyapulopapik@gmail.comKleshzz <vasyapulopapik@gmail.com> 2026-07-22 17:43:11+03:00
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-07-23 11:35:07+02:00
log97527a42c5a09564fa94d491a0c1d48c0fe66e28
treec2c1636021712768229b959a2c95f8832e5ad7eb
parent9a9d8adda017780956de9015db1858f48bc8f509

spirv: improve Assembler source locations, error formatting


1 files changed, 17 insertions(+), 18 deletions(-)

src/codegen/spirv/Assembler.zig+17-18
......@@ -24,6 +24,7 @@ inst: struct {
2424 opcode: Opcode = undefined,
2525 operands: std.ArrayList(Operand) = .empty,
2626 string_bytes: std.ArrayList(u8) = .empty,
27 inst_offset: u32 = 0,
2728
2829 fn result(ass: @This()) ?AsmValue.Ref {
2930 for (ass.operands.items[0..@min(ass.operands.items.len, 2)]) |op| {
......@@ -35,7 +36,7 @@ inst: struct {
3536 return null;
3637 }
3738} = .{},
38value_map: std.array_hash_map.String(AsmValue) = .{},
39value_map: std.array_hash_map.String(AsmValue) = .empty,
3940inst_map: std.array_hash_map.String(void) = .empty,
4041
4142const Operand = union(enum) {
......@@ -82,7 +83,7 @@ pub fn assemble(ass: *Assembler, src: []const u8) Error!void {
8283 if (ass.inst_map.count() == 0) {
8384 const instructions = spec.InstructionSet.core.instructions();
8485 try ass.inst_map.ensureUnusedCapacity(gpa, @intCast(instructions.len));
85 for (spec.InstructionSet.core.instructions(), 0..) |inst, i| {
86 for (instructions, 0..) |inst, i| {
8687 const entry = try ass.inst_map.getOrPut(gpa, inst.name);
8788 assert(entry.index == i);
8889 }
......@@ -114,12 +115,13 @@ fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytyp
114115}
115116
116117fn fail(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) Error {
118 @branchHint(.cold);
117119 try ass.addError(offset, fmt, args);
118120 return error.AssembleFail;
119121}
120122
121123fn todo(ass: *Assembler, comptime fmt: []const u8, args: anytype) Error {
122 return ass.fail(0, "todo: " ++ fmt, args);
124 return ass.fail(ass.inst.inst_offset, "todo: " ++ fmt, args);
123125}
124126
125127const AsmValue = union(enum) {
......@@ -209,9 +211,8 @@ fn processInstruction(ass: *Assembler) !void {
209211 switch (ass.value_map.values()[result_ref]) {
210212 .just_declared => ass.value_map.values()[result_ref] = result,
211213 else => {
212 // TODO: Improve source location.
213214 const name = ass.value_map.keys()[result_ref];
214 return ass.fail(0, "duplicate definition of %{s}", .{name});
215 return ass.fail(ass.inst.inst_offset, "duplicate definition of %{s}", .{name});
215216 },
216217 }
217218}
......@@ -229,12 +230,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
229230 0 => .unsigned,
230231 1 => .signed,
231232 else => {
232 // TODO: Improve source location.
233 return ass.fail(0, "{} is not a valid signedness (expected 0 or 1)", .{operands[2].literal32});
233 return ass.fail(ass.inst.inst_offset, "{} is not a valid signedness (expected 0 or 1)", .{operands[2].literal32});
234234 },
235235 };
236236 const width = std.math.cast(u16, operands[1].literal32) orelse {
237 return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32});
237 return ass.fail(ass.inst.inst_offset, "int type of {} bits is too large", .{operands[1].literal32});
238238 };
239239 break :blk try cg.intType(signedness, width);
240240 },
......@@ -243,7 +243,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue {
243243 switch (bits) {
244244 16, 32, 64 => {},
245245 else => {
246 return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
246 return ass.fail(ass.inst.inst_offset, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits});
247247 },
248248 }
249249 break :blk try cg.floatType(@intCast(bits));
......@@ -445,11 +445,11 @@ fn processSpecConstVector(ass: *Assembler) !?AsmValue {
445445 const gpa = cg.gpa;
446446 const ty_ref = switch (ass.inst.operands.items[0]) {
447447 .ref_id => |i| i,
448 else => return ass.fail(0, "missing result type", .{}),
448 else => return ass.fail(ass.inst.inst_offset, "missing result type", .{}),
449449 };
450450 const composite_ty_id = switch (try ass.resolveRef(ty_ref)) {
451451 .ty => |id| id,
452 else => return ass.fail(0, "%ty must be a type", .{}),
452 else => return ass.fail(ass.inst.inst_offset, "%ty must be a type", .{}),
453453 };
454454
455455 const globals = &cg.sections.globals;
......@@ -483,7 +483,7 @@ fn processSpecConstVector(ass: *Assembler) !?AsmValue {
483483 }
484484
485485 const spec_id_word = std.math.cast(u32, spec_id_base + i) orelse {
486 return ass.fail(0, "SpecId {} does not fit in 32 bits", .{spec_id_base + i});
486 return ass.fail(ass.inst.inst_offset, "SpecId {} does not fit in 32 bits", .{spec_id_base + i});
487487 };
488488 try annotations.emitRaw(gpa, .OpDecorate, 3);
489489 annotations.writeOperand(Id, elem_id);
......@@ -505,8 +505,7 @@ fn resolveMaybeForwardRef(ass: *Assembler, ref: AsmValue.Ref) !AsmValue {
505505 switch (value) {
506506 .just_declared => {
507507 const name = ass.value_map.keys()[ref];
508 // TODO: Improve source location.
509 return ass.fail(0, "ass-referential parameter %{s}", .{name});
508 return ass.fail(ass.inst.inst_offset, "self-referential parameter %{s}", .{name});
510509 },
511510 else => return value,
512511 }
......@@ -518,8 +517,7 @@ fn resolveRef(ass: *Assembler, ref: AsmValue.Ref) !AsmValue {
518517 .just_declared => unreachable,
519518 .unresolved_forward_reference => {
520519 const name = ass.value_map.keys()[ref];
521 // TODO: Improve source location.
522 return ass.fail(0, "reference to undeclared result-id %{s}", .{name});
520 return ass.fail(ass.inst.inst_offset, "reference to undeclared result-id %{s}", .{name});
523521 },
524522 else => return value,
525523 }
......@@ -536,6 +534,7 @@ fn parseInstruction(ass: *Assembler) !void {
536534 ass.inst.opcode = undefined;
537535 ass.inst.operands.clearRetainingCapacity();
538536 ass.inst.string_bytes.clearRetainingCapacity();
537 ass.inst.inst_offset = ass.currentToken().start;
539538
540539 const lhs_result_tok = ass.currentToken();
541540 const maybe_lhs_result: ?AsmValue.Ref = if (ass.eatToken(.result_id_assign)) blk: {
......@@ -589,8 +588,8 @@ fn parseInstruction(ass: *Assembler) !void {
589588 .required => if (ass.isAtInstructionBoundary()) {
590589 return ass.fail(
591590 ass.currentToken().start,
592 "missing required operand", // TODO: Operand name?
593 .{},
591 "missing required operand '{s}'",
592 .{@tagName(operand.kind)},
594593 );
595594 } else {
596595 try ass.parseOperand(operand.kind);