| ... | @@ -151,7 +151,8 @@ gpa: Allocator, | ... | @@ -151,7 +151,8 @@ gpa: Allocator, |
| 151 | errors: std.ArrayListUnmanaged(ErrorMsg) = .empty, | 151 | errors: std.ArrayListUnmanaged(ErrorMsg) = .empty, |
| 152 | | 152 | |
| 153 | /// The source code that is being assembled. | 153 | /// The source code that is being assembled. |
| 154 | src: []const u8, | 154 | /// This is set when calling `assemble()`. |
| | 155 | src: []const u8 = undefined, |
| 155 | | 156 | |
| 156 | /// The module that this assembly is associated to. | 157 | /// The module that this assembly is associated to. |
| 157 | /// Instructions like OpType*, OpDecorate, etc are emitted into this module. | 158 | /// Instructions like OpType*, OpDecorate, etc are emitted into this module. |
| ... | @@ -211,7 +212,10 @@ pub fn deinit(self: *Assembler) void { | ... | @@ -211,7 +212,10 @@ pub fn deinit(self: *Assembler) void { |
| 211 | self.instruction_map.deinit(self.gpa); | 212 | self.instruction_map.deinit(self.gpa); |
| 212 | } | 213 | } |
| 213 | | 214 | |
| 214 | pub fn assemble(self: *Assembler) Error!void { | 215 | pub fn assemble(self: *Assembler, src: []const u8) Error!void { |
| | 216 | self.src = src; |
| | 217 | self.errors.clearRetainingCapacity(); |
| | 218 | |
| 215 | // Populate the opcode map if it isn't already | 219 | // Populate the opcode map if it isn't already |
| 216 | if (self.instruction_map.count() == 0) { | 220 | if (self.instruction_map.count() == 0) { |
| 217 | const instructions = spec.InstructionSet.core.instructions(); | 221 | const instructions = spec.InstructionSet.core.instructions(); |
| ... | @@ -369,6 +373,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { | ... | @@ -369,6 +373,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { |
| 369 | /// - Function-local instructions are emitted in `self.func`. | 373 | /// - Function-local instructions are emitted in `self.func`. |
| 370 | fn processGenericInstruction(self: *Assembler) !?AsmValue { | 374 | fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 371 | const operands = self.inst.operands.items; | 375 | const operands = self.inst.operands.items; |
| | 376 | var maybe_spv_decl_index: ?SpvModule.Decl.Index = null; |
| 372 | const section = switch (self.inst.opcode.class()) { | 377 | const section = switch (self.inst.opcode.class()) { |
| 373 | .ConstantCreation => &self.spv.sections.types_globals_constants, | 378 | .ConstantCreation => &self.spv.sections.types_globals_constants, |
| 374 | .Annotation => &self.spv.sections.annotations, | 379 | .Annotation => &self.spv.sections.annotations, |
| ... | @@ -378,12 +383,15 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { | ... | @@ -378,12 +383,15 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 378 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, | 383 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, |
| 379 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { | 384 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { |
| 380 | .Function => &self.func.prologue, | 385 | .Function => &self.func.prologue, |
| 381 | .UniformConstant => &self.spv.sections.types_globals_constants, | 386 | // These don't need to be marked in the dependency system. |
| 382 | else => { | 387 | // Probably we should add them anyway, then filter out PushConstant globals. |
| 383 | // This is currently disabled because global variables are required to be | 388 | .PushConstant => &self.spv.sections.types_globals_constants, |
| 384 | // emitted in the proper order, and this should be honored in inline assembly | 389 | else => section: { |
| 385 | // as well. | 390 | maybe_spv_decl_index = try self.spv.allocDecl(.global); |
| 386 | return self.todo("global variables", .{}); | 391 | try self.func.decl_deps.put(self.spv.gpa, maybe_spv_decl_index.?, {}); |
| | 392 | // TODO: In theory this can be non-empty if there is an initializer which depends on another global... |
| | 393 | try self.spv.declareDeclDeps(maybe_spv_decl_index.?, &.{}); |
| | 394 | break :section &self.spv.sections.types_globals_constants; |
| 387 | }, | 395 | }, |
| 388 | }, | 396 | }, |
| 389 | // Default case - to be worked out further. | 397 | // Default case - to be worked out further. |
| ... | @@ -409,7 +417,10 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { | ... | @@ -409,7 +417,10 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 409 | section.writeDoubleWord(dword); | 417 | section.writeDoubleWord(dword); |
| 410 | }, | 418 | }, |
| 411 | .result_id => { | 419 | .result_id => { |
| 412 | maybe_result_id = self.spv.allocId(); | 420 | maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index| |
| | 421 | self.spv.declPtr(spv_decl_index).result_id |
| | 422 | else |
| | 423 | self.spv.allocId(); |
| 413 | try section.ensureUnusedCapacity(self.spv.gpa, 1); | 424 | try section.ensureUnusedCapacity(self.spv.gpa, 1); |
| 414 | section.writeOperand(IdResult, maybe_result_id.?); | 425 | section.writeOperand(IdResult, maybe_result_id.?); |
| 415 | }, | 426 | }, |
| ... | @@ -475,8 +486,8 @@ fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !IdRef { | ... | @@ -475,8 +486,8 @@ fn resolveRefId(self: *Assembler, ref: AsmValue.Ref) !IdRef { |
| 475 | /// error message has been emitted into `self.errors`. | 486 | /// error message has been emitted into `self.errors`. |
| 476 | fn parseInstruction(self: *Assembler) !void { | 487 | fn parseInstruction(self: *Assembler) !void { |
| 477 | self.inst.opcode = undefined; | 488 | self.inst.opcode = undefined; |
| 478 | self.inst.operands.shrinkRetainingCapacity(0); | 489 | self.inst.operands.clearRetainingCapacity(); |
| 479 | self.inst.string_bytes.shrinkRetainingCapacity(0); | 490 | self.inst.string_bytes.clearRetainingCapacity(); |
| 480 | | 491 | |
| 481 | const lhs_result_tok = self.currentToken(); | 492 | const lhs_result_tok = self.currentToken(); |
| 482 | const maybe_lhs_result: ?AsmValue.Ref = if (self.eatToken(.result_id_assign)) blk: { | 493 | const maybe_lhs_result: ?AsmValue.Ref = if (self.eatToken(.result_id_assign)) blk: { |
| ... | @@ -848,6 +859,8 @@ fn tokenText(self: Assembler, tok: Token) []const u8 { | ... | @@ -848,6 +859,8 @@ fn tokenText(self: Assembler, tok: Token) []const u8 { |
| 848 | /// Tokenize `self.src` and put the tokens in `self.tokens`. | 859 | /// Tokenize `self.src` and put the tokens in `self.tokens`. |
| 849 | /// Any errors encountered are appended to `self.errors`. | 860 | /// Any errors encountered are appended to `self.errors`. |
| 850 | fn tokenize(self: *Assembler) !void { | 861 | fn tokenize(self: *Assembler) !void { |
| | 862 | self.tokens.clearRetainingCapacity(); |
| | 863 | |
| 851 | var offset: u32 = 0; | 864 | var offset: u32 = 0; |
| 852 | while (true) { | 865 | while (true) { |
| 853 | const tok = try self.nextToken(offset); | 866 | const tok = try self.nextToken(offset); |