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