| ... | @@ -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, |
| 28 | | 28 | |
| 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 { |
| 366 | | 366 | |
| 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 is | 369 | |
| 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); |
| 373 | | 385 | |
| 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_id | 392 | cg.declPtr(spv_decl_index).result_id |
| 387 | else | 393 | 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 | } |