| ... | @@ -194,6 +194,11 @@ inst: struct { | ... | @@ -194,6 +194,11 @@ inst: struct { |
| 194 | /// This map maps results to their tracked values. | 194 | /// This map maps results to their tracked values. |
| 195 | value_map: AsmValueMap = .{}, | 195 | value_map: AsmValueMap = .{}, |
| 196 | | 196 | |
| | 197 | /// This set is used to quickly transform from an opcode name to the |
| | 198 | /// index in its instruction set. The index of the key is the |
| | 199 | /// index in `spec.InstructionSet.core.instructions()`. |
| | 200 | instruction_map: std.StringArrayHashMapUnmanaged(void) = .{}, |
| | 201 | |
| 197 | /// Free the resources owned by this assembler. | 202 | /// Free the resources owned by this assembler. |
| 198 | pub fn deinit(self: *Assembler) void { | 203 | pub fn deinit(self: *Assembler) void { |
| 199 | for (self.errors.items) |err| { | 204 | for (self.errors.items) |err| { |
| ... | @@ -204,9 +209,20 @@ pub fn deinit(self: *Assembler) void { | ... | @@ -204,9 +209,20 @@ pub fn deinit(self: *Assembler) void { |
| 204 | self.inst.operands.deinit(self.gpa); | 209 | self.inst.operands.deinit(self.gpa); |
| 205 | self.inst.string_bytes.deinit(self.gpa); | 210 | self.inst.string_bytes.deinit(self.gpa); |
| 206 | self.value_map.deinit(self.gpa); | 211 | self.value_map.deinit(self.gpa); |
| | 212 | self.instruction_map.deinit(self.gpa); |
| 207 | } | 213 | } |
| 208 | | 214 | |
| 209 | pub fn assemble(self: *Assembler) Error!void { | 215 | pub fn assemble(self: *Assembler) Error!void { |
| | 216 | // Populate the opcode map if it isn't already |
| | 217 | if (self.instruction_map.count() == 0) { |
| | 218 | const instructions = spec.InstructionSet.core.instructions(); |
| | 219 | try self.instruction_map.ensureUnusedCapacity(self.gpa, @intCast(instructions.len)); |
| | 220 | for (spec.InstructionSet.core.instructions(), 0..) |inst, i| { |
| | 221 | const entry = try self.instruction_map.getOrPut(self.gpa, inst.name); |
| | 222 | assert(entry.index == i); |
| | 223 | } |
| | 224 | } |
| | 225 | |
| 210 | try self.tokenize(); | 226 | try self.tokenize(); |
| 211 | while (!self.testToken(.eof)) { | 227 | while (!self.testToken(.eof)) { |
| 212 | try self.parseInstruction(); | 228 | try self.parseInstruction(); |
| ... | @@ -475,12 +491,14 @@ fn parseInstruction(self: *Assembler) !void { | ... | @@ -475,12 +491,14 @@ fn parseInstruction(self: *Assembler) !void { |
| 475 | } | 491 | } |
| 476 | | 492 | |
| 477 | const opcode_text = self.tokenText(opcode_tok); | 493 | const opcode_text = self.tokenText(opcode_tok); |
| 478 | @setEvalBranchQuota(10000); | 494 | const index = self.instruction_map.getIndex(opcode_text) orelse { |
| 479 | self.inst.opcode = std.meta.stringToEnum(Opcode, opcode_text) orelse { | | |
| 480 | return self.fail(opcode_tok.start, "invalid opcode '{s}'", .{opcode_text}); | 495 | return self.fail(opcode_tok.start, "invalid opcode '{s}'", .{opcode_text}); |
| 481 | }; | 496 | }; |
| 482 | | 497 | |
| 483 | const expected_operands = self.inst.opcode.operands(); | 498 | const inst = spec.InstructionSet.core.instructions()[index]; |
| | 499 | self.inst.opcode = @enumFromInt(inst.opcode); |
| | 500 | |
| | 501 | const expected_operands = inst.operands; |
| 484 | // This is a loop because the result-id is not always the first operand. | 502 | // This is a loop because the result-id is not always the first operand. |
| 485 | const requires_lhs_result = for (expected_operands) |op| { | 503 | const requires_lhs_result = for (expected_operands) |op| { |
| 486 | if (op.kind == .IdResult) break true; | 504 | if (op.kind == .IdResult) break true; |