SPIR-V: Split out registry from gen_spirv_spec.zig

This commit is contained in:
Robin Voetter 2021-05-12 00:08:14 +02:00
parent 42f2ff6ec9
commit 25329ca852
2 changed files with 97 additions and 97 deletions

View file

@ -1,97 +1,7 @@
const std = @import("std"); const std = @import("std");
const g = @import("spirv/grammar.zig");
const Writer = std.ArrayList(u8).Writer; const Writer = std.ArrayList(u8).Writer;
//! See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
//! and the files in https://github.com/KhronosGroup/SPIRV-Headers/blob/master/include/spirv/unified1/
//! Note: Non-canonical casing in these structs used to match SPIR-V spec json.
const Registry = union(enum) {
core: CoreRegistry,
extension: ExtensionRegistry,
};
const CoreRegistry = struct {
copyright: [][]const u8,
/// Hexadecimal representation of the magic number
magic_number: []const u8,
major_version: u32,
minor_version: u32,
revision: u32,
instruction_printing_class: []InstructionPrintingClass,
instructions: []Instruction,
operand_kinds: []OperandKind,
};
const ExtensionRegistry = struct {
copyright: [][]const u8,
version: u32,
revision: u32,
instructions: []Instruction,
operand_kinds: []OperandKind = &[_]OperandKind{},
};
const InstructionPrintingClass = struct {
tag: []const u8,
heading: ?[]const u8 = null,
};
const Instruction = struct {
opname: []const u8,
class: ?[]const u8 = null, // Note: Only available in the core registry.
opcode: u32,
operands: []Operand = &[_]Operand{},
capabilities: [][]const u8 = &[_][]const u8{},
extensions: [][]const u8 = &[_][]const u8{},
version: ?[]const u8 = null,
lastVersion: ?[]const u8 = null,
};
const Operand = struct {
kind: []const u8,
/// If this field is 'null', the operand is only expected once.
quantifier: ?Quantifier = null,
name: []const u8 = "",
};
const Quantifier = enum {
/// zero or once
@"?",
/// zero or more
@"*",
};
const OperandCategory = enum {
BitEnum,
ValueEnum,
Id,
Literal,
Composite,
};
const OperandKind = struct {
category: OperandCategory,
/// The name
kind: []const u8,
doc: ?[]const u8 = null,
enumerants: ?[]Enumerant = null,
bases: ?[]const []const u8 = null,
};
const Enumerant = struct {
enumerant: []const u8,
value: union(enum) {
bitflag: []const u8, // Hexadecimal representation of the value
int: u31,
},
capabilities: [][]const u8 = &[_][]const u8{},
/// Valid for .ValueEnum and .BitEnum
extensions: [][]const u8 = &[_][]const u8{},
/// `quantifier` will always be `null`.
parameters: []Operand = &[_]Operand{},
version: ?[]const u8 = null,
lastVersion: ?[]const u8 = null,
};
pub fn main() !void { pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
@ -106,7 +16,7 @@ pub fn main() !void {
const spec = try std.fs.cwd().readFileAlloc(allocator, spec_path, std.math.maxInt(usize)); const spec = try std.fs.cwd().readFileAlloc(allocator, spec_path, std.math.maxInt(usize));
var tokens = std.json.TokenStream.init(spec); var tokens = std.json.TokenStream.init(spec);
var registry = try std.json.parse(Registry, &tokens, .{.allocator = allocator}); var registry = try std.json.parse(g.Registry, &tokens, .{.allocator = allocator});
var buf = std.ArrayList(u8).init(allocator); var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit(); defer buf.deinit();
@ -118,7 +28,7 @@ pub fn main() !void {
try std.io.getStdOut().writeAll(formatted); try std.io.getStdOut().writeAll(formatted);
} }
fn render(writer: Writer, registry: Registry) !void { fn render(writer: Writer, registry: g.Registry) !void {
try writer.writeAll( try writer.writeAll(
\\//! This file is auto-generated by tools/gen_spirv_spec.zig. \\//! This file is auto-generated by tools/gen_spirv_spec.zig.
\\ \\
@ -149,7 +59,7 @@ fn render(writer: Writer, registry: Registry) !void {
} }
} }
fn renderOpcodes(writer: Writer, instructions: []const Instruction) !void { fn renderOpcodes(writer: Writer, instructions: []const g.Instruction) !void {
try writer.writeAll("pub const Opcode = extern enum(u16) {\n"); try writer.writeAll("pub const Opcode = extern enum(u16) {\n");
for (instructions) |instr| { for (instructions) |instr| {
try writer.print("{} = {},\n", .{ std.zig.fmtId(instr.opname), instr.opcode }); try writer.print("{} = {},\n", .{ std.zig.fmtId(instr.opname), instr.opcode });
@ -157,7 +67,7 @@ fn renderOpcodes(writer: Writer, instructions: []const Instruction) !void {
try writer.writeAll("_,\n};\n"); try writer.writeAll("_,\n};\n");
} }
fn renderOperandKinds(writer: Writer, kinds: []const OperandKind) !void { fn renderOperandKinds(writer: Writer, kinds: []const g.OperandKind) !void {
for (kinds) |kind| { for (kinds) |kind| {
switch (kind.category) { switch (kind.category) {
.ValueEnum => try renderValueEnum(writer, kind), .ValueEnum => try renderValueEnum(writer, kind),
@ -167,7 +77,7 @@ fn renderOperandKinds(writer: Writer, kinds: []const OperandKind) !void {
} }
} }
fn renderValueEnum(writer: Writer, enumeration: OperandKind) !void { fn renderValueEnum(writer: Writer, enumeration: g.OperandKind) !void {
try writer.print("pub const {s} = extern enum(u32) {{\n", .{ enumeration.kind }); try writer.print("pub const {s} = extern enum(u32) {{\n", .{ enumeration.kind });
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry; const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
@ -180,7 +90,7 @@ fn renderValueEnum(writer: Writer, enumeration: OperandKind) !void {
try writer.writeAll("_,\n};\n"); try writer.writeAll("_,\n};\n");
} }
fn renderBitEnum(writer: Writer, enumeration: OperandKind) !void { fn renderBitEnum(writer: Writer, enumeration: g.OperandKind) !void {
try writer.print("pub const {s} = packed struct {{\n", .{ enumeration.kind }); try writer.print("pub const {s} = packed struct {{\n", .{ enumeration.kind });
var flags_by_bitpos = [_]?[]const u8{null} ** 32; var flags_by_bitpos = [_]?[]const u8{null} ** 32;

90
tools/spirv/grammar.zig Normal file
View file

@ -0,0 +1,90 @@
//! See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html
//! and the files in https://github.com/KhronosGroup/SPIRV-Headers/blob/master/include/spirv/unified1/
//! Note: Non-canonical casing in these structs used to match SPIR-V spec json.
pub const Registry = union(enum) {
core: CoreRegistry,
extension: ExtensionRegistry,
};
pub const CoreRegistry = struct {
copyright: [][]const u8,
/// Hexadecimal representation of the magic number
magic_number: []const u8,
major_version: u32,
minor_version: u32,
revision: u32,
instruction_printing_class: []InstructionPrintingClass,
instructions: []Instruction,
operand_kinds: []OperandKind,
};
pub const ExtensionRegistry = struct {
copyright: [][]const u8,
version: u32,
revision: u32,
instructions: []Instruction,
operand_kinds: []OperandKind = &[_]OperandKind{},
};
pub const InstructionPrintingClass = struct {
tag: []const u8,
heading: ?[]const u8 = null,
};
pub const Instruction = struct {
opname: []const u8,
class: ?[]const u8 = null, // Note: Only available in the core registry.
opcode: u32,
operands: []Operand = &[_]Operand{},
capabilities: [][]const u8 = &[_][]const u8{},
extensions: [][]const u8 = &[_][]const u8{},
version: ?[]const u8 = null,
lastVersion: ?[]const u8 = null,
};
pub const Operand = struct {
kind: []const u8,
/// If this field is 'null', the operand is only expected once.
quantifier: ?Quantifier = null,
name: []const u8 = "",
};
pub const Quantifier = enum {
/// zero or once
@"?",
/// zero or more
@"*",
};
pub const OperandCategory = enum {
BitEnum,
ValueEnum,
Id,
Literal,
Composite,
};
pub const OperandKind = struct {
category: OperandCategory,
/// The name
kind: []const u8,
doc: ?[]const u8 = null,
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{},
/// Valid for .ValueEnum and .BitEnum
extensions: [][]const u8 = &[_][]const u8{},
/// `quantifier` will always be `null`.
parameters: []Operand = &[_]Operand{},
version: ?[]const u8 = null,
lastVersion: ?[]const u8 = null,
};