diff --git a/generator/spirv/generator.zig b/generator/spirv/generator.zig deleted file mode 100644 index ea7d97b..0000000 --- a/generator/spirv/generator.zig +++ /dev/null @@ -1,73 +0,0 @@ -const std = @import("std"); -const reg = @import("registry.zig"); -const renderSpirv = @import("render.zig").render; -const Allocator = std.mem.Allocator; - -pub fn mergeRegistries(allocator: *Allocator, core: reg.CoreRegistry, extensions: []const reg.ExtensionRegistry) !reg.CoreRegistry { - var merged = core; - - var total_instructions = core.instructions.len; - var total_operand_kinds = core.operand_kinds.len; - for (extensions) |ext| { - total_instructions += ext.instructions.len; - total_operand_kinds += ext.operand_kinds.len; - } - - merged.instructions = try allocator.alloc(reg.Instruction, total_instructions); - merged.operand_kinds = try allocator.alloc(reg.OperandKind, total_operand_kinds); - - // Assume the core and extension registries contain no common operand kinds and instructions. - for (core.instructions) |inst, i| merged.instructions[i] = inst; - for (core.operand_kinds) |operand_kind, i| merged.operand_kinds[i] = operand_kind; - - var inst_i = core.instructions.len; - var oper_i = core.operand_kinds.len; - - for (extensions) |ext| { - for (ext.instructions) |inst| { - merged.instructions[inst_i] = inst; - inst_i += 1; - } - - for (ext.operand_kinds) |operand_kind| { - merged.operand_kinds[oper_i] = operand_kind; - oper_i += 1; - } - } - - return merged; -} - -pub fn generate(allocator: *Allocator, spec_jsons: []const []const u8, writer: anytype) !void { - var arena = std.heap.ArenaAllocator.init(allocator); - defer arena.deinit(); - - // Exactly one of the passed specs must be core - the others must be exensions. - var core_registry: reg.CoreRegistry = undefined; - const num_ext_registries = spec_jsons.len - 1; - const ext_registries = try arena.allocator.alloc(reg.ExtensionRegistry, num_ext_registries); - - var ext_registry_i: usize = 0; - for (spec_jsons) |spec_json| { - var tokens = std.json.TokenStream.init(spec_json); - const registry = try std.json.parse(reg.Registry, &tokens, .{.allocator = &arena.allocator}); - switch (registry) { - .core => |parsed_core_registry| core_registry = parsed_core_registry, - .extension => |parsed_ext_registry| { - if (ext_registry_i == num_ext_registries) { - return error.NoCoreRegistry; - } - - ext_registries[ext_registry_i] = parsed_ext_registry; - ext_registry_i += 1; - }, - } - } - - if (ext_registry_i != num_ext_registries) { - return error.MultipleCoreRegistries; - } - - const merged = try mergeRegistries(&arena.allocator, core_registry, ext_registries); - try renderSpirv(writer, &arena.allocator, &merged); -} diff --git a/generator/spirv/registry.zig b/generator/spirv/registry.zig deleted file mode 100644 index 4f89f07..0000000 --- a/generator/spirv/registry.zig +++ /dev/null @@ -1,71 +0,0 @@ -// See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html - -pub const Registry = union(enum) { - core: CoreRegistry, - extension: ExtensionRegistry, -}; - -pub const CoreRegistry = struct { - copyright: [][]const u8, - magic_number: []const u8, // Hexadecimal representation of the magic number - major_version: u32, - minor_version: u32, - revision: u32, - instructions: []Instruction, - operand_kinds: []OperandKind, -}; - -pub const ExtensionRegistry = struct { - copyright: [][]const u8, - version: u32, - revision: u32, - instructions: []Instruction, - operand_kinds: []OperandKind = &[_]OperandKind{}, -}; - -pub const Instruction = struct { - opname: []const u8, - opcode: u32, - operands: []Operand = &[_]Operand{}, - capabilities: [][]const u8 = &[_][]const u8{}, - extensions: [][]const u8 = &[_][]const u8{}, -}; - -pub const Operand = struct { - kind: []const u8, - - /// Either - /// - null: exactly once. - /// - "?": zero or once. - /// - "*": zero or more. - quantifier: ?[]const u8 = null, - name: []const u8 = "", -}; - -pub const OperandCategory = enum { - // Note: non-canonical casing to match Spir-V JSON spec/ - BitEnum, - ValueEnum, - Id, - Literal, - Composite, -}; - -pub const OperandKind = struct { - category: OperandCategory, - kind: []const u8, - doc: []const u8 = "", - enumerants: ?[]Enumerant = null, - bases: ?[]const []const u8 = null, -}; - -pub const Enumerant = struct { - enumerant: []const u8, - value: union(enum) { - bitflag: []const u8, // Hexadecimal representation of the value - int: u31, - }, - capabilities: [][]const u8 = &[_][]const u8{}, - extensions: [][]const u8 = &[_][]const u8{}, // Valid for .ValueEnum - parameters: []Operand = &[_]Operand{}, // `quantifier` will always be `null`. -}; diff --git a/generator/spirv/render.zig b/generator/spirv/render.zig deleted file mode 100644 index 6ec24e5..0000000 --- a/generator/spirv/render.zig +++ /dev/null @@ -1,69 +0,0 @@ -const std = @import("std"); -const reg = @import("registry.zig"); -const IdRenderer = @import("../id_render.zig").IdRenderer; -const Allocator = std.mem.Allocator; - -// The SPIR-V spec doesn't contain any tag information like vulkan.xml does, -// so the tags are just hardcoded. They are retrieved from -// https://github.com/KhronosGroup/SPIRV-Registry/tree/master/extensions -const tags = [_][]const u8{ - "AMD", - "EXT", - "GOOGLE", - "INTEL", - "KHR", - "NV", -}; - -const preamble = - \\ - \\ This file is generated from the SPIR-V JSON registry - ; - -fn stripOpPrefix(name: []const u8) []const u8 { - // Some instructions (those from the core) are prefixed with 'Op' - const prefix = "Op"; - return if (std.mem.startsWith(u8, name, prefix)) - name[prefix.len ..] - else - name; -} - -fn Renderer(comptime WriterType: type) type { - return struct { - const Self = @This(); - - writer: WriterType, - registry: *const reg.CoreRegistry, - id_renderer: IdRenderer, - - fn render(self: *Self) !void { - for (self.registry.copyright) |line| { - try self.writer.print("// {}\n", .{ line }); - } - try self.writer.writeAll(preamble); - try self.renderOpcodes(); - } - - fn renderOpcodes(self: *Self) !void { - try self.writer.writeAll("pub const Opcode = enum(u16) {\n"); - for (self.registry.instructions) |instr| { - try self.id_renderer.renderWithCase(self.writer, .snake, stripOpPrefix(instr.opname)); - try self.writer.print(" = {},\n", .{ instr.opcode }); - } - try self.writer.writeAll("};\n"); - } - }; -} - -pub fn render(writer: anytype, allocator: *Allocator, registry: *const reg.CoreRegistry) !void { - const id_renderer = IdRenderer.init(allocator, &tags); - defer id_renderer.deinit(); - var renderer = Renderer(@TypeOf(writer)) { - .writer = writer, - .registry = registry, - .id_renderer = id_renderer, - }; - try renderer.render(); -} -