spirv: snake-case the spec
This commit is contained in:
committed by
Alex Rønne Petersen
parent
2f3cd175d3
commit
f43f89a705
@@ -59,26 +59,28 @@ const set_names = std.StaticStringMap([]const u8).initComptime(.{
|
||||
.{ "nonsemantic.debugprintf", "NonSemantic.DebugPrintf" },
|
||||
.{ "spv-amd-shader-explicit-vertex-parameter", "SPV_AMD_shader_explicit_vertex_parameter" },
|
||||
.{ "nonsemantic.debugbreak", "NonSemantic.DebugBreak" },
|
||||
.{ "tosa.001000.1", "SPV_EXT_INST_TYPE_TOSA_001000_1" },
|
||||
.{ "zig", "zig" },
|
||||
});
|
||||
|
||||
pub fn main() !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const a = arena.allocator();
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.smp_allocator);
|
||||
const allocator = arena.allocator();
|
||||
|
||||
const args = try std.process.argsAlloc(a);
|
||||
pub fn main() !void {
|
||||
defer arena.deinit();
|
||||
|
||||
const args = try std.process.argsAlloc(allocator);
|
||||
if (args.len != 3) {
|
||||
usageAndExit(args[0], 1);
|
||||
}
|
||||
|
||||
const json_path = try std.fs.path.join(a, &.{ args[1], "include/spirv/unified1/" });
|
||||
const json_path = try std.fs.path.join(allocator, &.{ args[1], "include/spirv/unified1/" });
|
||||
const dir = try std.fs.cwd().openDir(json_path, .{ .iterate = true });
|
||||
|
||||
const core_spec = try readRegistry(CoreRegistry, a, dir, "spirv.core.grammar.json");
|
||||
const core_spec = try readRegistry(CoreRegistry, dir, "spirv.core.grammar.json");
|
||||
std.sort.block(Instruction, core_spec.instructions, CmpInst{}, CmpInst.lt);
|
||||
|
||||
var exts = std.ArrayList(Extension).init(a);
|
||||
var exts = std.ArrayList(Extension).init(allocator);
|
||||
|
||||
var it = dir.iterate();
|
||||
while (try it.next()) |entry| {
|
||||
@@ -86,18 +88,43 @@ pub fn main() !void {
|
||||
continue;
|
||||
}
|
||||
|
||||
try readExtRegistry(&exts, a, dir, entry.name);
|
||||
try readExtRegistry(&exts, dir, entry.name);
|
||||
}
|
||||
|
||||
try readExtRegistry(&exts, a, std.fs.cwd(), args[2]);
|
||||
try readExtRegistry(&exts, std.fs.cwd(), args[2]);
|
||||
|
||||
var buffer: [4000]u8 = undefined;
|
||||
var w = std.fs.File.stdout().writerStreaming(&buffer);
|
||||
try render(&w, a, core_spec, exts.items);
|
||||
try w.flush();
|
||||
const output_buf = try allocator.alloc(u8, 1024 * 1024);
|
||||
var fbs = std.io.fixedBufferStream(output_buf);
|
||||
var adapter = fbs.writer().adaptToNewApi();
|
||||
const w = &adapter.new_interface;
|
||||
try render(w, core_spec, exts.items);
|
||||
var output: [:0]u8 = @ptrCast(fbs.getWritten());
|
||||
output[output.len] = 0;
|
||||
|
||||
var tree = try std.zig.Ast.parse(allocator, output, .zig);
|
||||
var color: std.zig.Color = .on;
|
||||
|
||||
if (tree.errors.len != 0) {
|
||||
try std.zig.printAstErrorsToStderr(allocator, tree, "", color);
|
||||
return;
|
||||
}
|
||||
|
||||
var zir = try std.zig.AstGen.generate(allocator, tree);
|
||||
if (zir.hasCompileErrors()) {
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(allocator);
|
||||
defer wip_errors.deinit();
|
||||
try wip_errors.addZirErrorMessages(zir, tree, output, "");
|
||||
var error_bundle = try wip_errors.toOwnedBundle("");
|
||||
defer error_bundle.deinit(allocator);
|
||||
error_bundle.renderToStdErr(color.renderOptions());
|
||||
}
|
||||
|
||||
const formatted_output = try tree.render(allocator);
|
||||
_ = try std.fs.File.stdout().write(formatted_output);
|
||||
}
|
||||
|
||||
fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Dir, sub_path: []const u8) !void {
|
||||
fn readExtRegistry(exts: *std.ArrayList(Extension), dir: std.fs.Dir, sub_path: []const u8) !void {
|
||||
const filename = std.fs.path.basename(sub_path);
|
||||
if (!std.mem.startsWith(u8, filename, "extinst.")) {
|
||||
return;
|
||||
@@ -105,22 +132,22 @@ fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Di
|
||||
|
||||
std.debug.assert(std.mem.endsWith(u8, filename, ".grammar.json"));
|
||||
const name = filename["extinst.".len .. filename.len - ".grammar.json".len];
|
||||
const spec = try readRegistry(ExtensionRegistry, a, dir, sub_path);
|
||||
const spec = try readRegistry(ExtensionRegistry, dir, sub_path);
|
||||
|
||||
std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);
|
||||
|
||||
try exts.append(.{ .name = set_names.get(name).?, .spec = spec });
|
||||
}
|
||||
|
||||
fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path: []const u8) !RegistryType {
|
||||
const spec = try dir.readFileAlloc(a, path, std.math.maxInt(usize));
|
||||
fn readRegistry(comptime RegistryType: type, dir: std.fs.Dir, path: []const u8) !RegistryType {
|
||||
const spec = try dir.readFileAlloc(allocator, path, std.math.maxInt(usize));
|
||||
// Required for json parsing.
|
||||
@setEvalBranchQuota(10000);
|
||||
|
||||
var scanner = std.json.Scanner.initCompleteInput(a, spec);
|
||||
var scanner = std.json.Scanner.initCompleteInput(allocator, spec);
|
||||
var diagnostics = std.json.Diagnostics{};
|
||||
scanner.enableDiagnostics(&diagnostics);
|
||||
const parsed = std.json.parseFromTokenSource(RegistryType, a, &scanner, .{}) catch |err| {
|
||||
const parsed = std.json.parseFromTokenSource(RegistryType, allocator, &scanner, .{}) catch |err| {
|
||||
std.debug.print("{s}:{}:{}:\n", .{ path, diagnostics.getLine(), diagnostics.getColumn() });
|
||||
return err;
|
||||
};
|
||||
@@ -129,11 +156,8 @@ fn readRegistry(comptime RegistryType: type, a: Allocator, dir: std.fs.Dir, path
|
||||
|
||||
/// Returns a set with types that require an extra struct for the `Instruction` interface
|
||||
/// to the spir-v spec, or whether the original type can be used.
|
||||
fn extendedStructs(
|
||||
a: Allocator,
|
||||
kinds: []const OperandKind,
|
||||
) !ExtendedStructSet {
|
||||
var map = ExtendedStructSet.init(a);
|
||||
fn extendedStructs(kinds: []const OperandKind) !ExtendedStructSet {
|
||||
var map = ExtendedStructSet.init(allocator);
|
||||
try map.ensureTotalCapacity(@as(u32, @intCast(kinds.len)));
|
||||
|
||||
for (kinds) |kind| {
|
||||
@@ -167,7 +191,7 @@ fn tagPriorityScore(tag: []const u8) usize {
|
||||
}
|
||||
}
|
||||
|
||||
fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensions: []const Extension) !void {
|
||||
fn render(writer: *std.io.Writer, registry: CoreRegistry, extensions: []const Extension) !void {
|
||||
try writer.writeAll(
|
||||
\\//! This file is auto-generated by tools/gen_spirv_spec.zig.
|
||||
\\
|
||||
@@ -185,22 +209,17 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
||||
\\};
|
||||
\\
|
||||
\\pub const Word = u32;
|
||||
\\pub const IdResult = enum(Word) {
|
||||
\\pub const Id = enum(Word) {
|
||||
\\ none,
|
||||
\\ _,
|
||||
\\
|
||||
\\ pub fn format(self: IdResult, writer: *std.io.Writer) std.io.Writer.Error!void {
|
||||
\\ pub fn format(self: Id, writer: *std.io.Writer) std.io.Writer.Error!void {
|
||||
\\ switch (self) {
|
||||
\\ .none => try writer.writeAll("(none)"),
|
||||
\\ else => try writer.print("%{d}", .{@intFromEnum(self)}),
|
||||
\\ }
|
||||
\\ }
|
||||
\\};
|
||||
\\pub const IdResultType = IdResult;
|
||||
\\pub const IdRef = IdResult;
|
||||
\\
|
||||
\\pub const IdMemorySemantics = IdRef;
|
||||
\\pub const IdScope = IdRef;
|
||||
\\
|
||||
\\pub const LiteralInteger = Word;
|
||||
\\pub const LiteralFloat = Word;
|
||||
@@ -215,9 +234,9 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
||||
\\};
|
||||
\\pub const LiteralExtInstInteger = struct{ inst: Word };
|
||||
\\pub const LiteralSpecConstantOpInteger = struct { opcode: Opcode };
|
||||
\\pub const PairLiteralIntegerIdRef = struct { value: LiteralInteger, label: IdRef };
|
||||
\\pub const PairIdRefLiteralInteger = struct { target: IdRef, member: LiteralInteger };
|
||||
\\pub const PairIdRefIdRef = [2]IdRef;
|
||||
\\pub const PairLiteralIntegerIdRef = struct { value: LiteralInteger, label: Id };
|
||||
\\pub const PairIdRefLiteralInteger = struct { target: Id, member: LiteralInteger };
|
||||
\\pub const PairIdRefIdRef = [2]Id;
|
||||
\\
|
||||
\\pub const Quantifier = enum {
|
||||
\\ required,
|
||||
@@ -255,7 +274,7 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
||||
);
|
||||
|
||||
try writer.print(
|
||||
\\pub const version = Version{{ .major = {}, .minor = {}, .patch = {} }};
|
||||
\\pub const version: Version = .{{ .major = {}, .minor = {}, .patch = {} }};
|
||||
\\pub const magic_number: Word = {s};
|
||||
\\
|
||||
\\
|
||||
@@ -266,7 +285,7 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
||||
// Merge the operand kinds from all extensions together.
|
||||
// var all_operand_kinds = std.ArrayList(OperandKind).init(a);
|
||||
// try all_operand_kinds.appendSlice(registry.operand_kinds);
|
||||
var all_operand_kinds = OperandKindMap.init(a);
|
||||
var all_operand_kinds = OperandKindMap.init(allocator);
|
||||
for (registry.operand_kinds) |kind| {
|
||||
try all_operand_kinds.putNoClobber(.{ "core", kind.kind }, kind);
|
||||
}
|
||||
@@ -279,35 +298,33 @@ fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensio
|
||||
try all_operand_kinds.ensureUnusedCapacity(ext.spec.operand_kinds.len);
|
||||
for (ext.spec.operand_kinds) |kind| {
|
||||
var new_kind = kind;
|
||||
new_kind.kind = try std.mem.join(a, ".", &.{ ext.name, kind.kind });
|
||||
new_kind.kind = try std.mem.join(allocator, ".", &.{ ext.name, kind.kind });
|
||||
try all_operand_kinds.putNoClobber(.{ ext.name, kind.kind }, new_kind);
|
||||
}
|
||||
}
|
||||
|
||||
const extended_structs = try extendedStructs(a, all_operand_kinds.values());
|
||||
const extended_structs = try extendedStructs(all_operand_kinds.values());
|
||||
// Note: extensions don't seem to have class.
|
||||
try renderClass(writer, a, registry.instructions);
|
||||
try renderClass(writer, registry.instructions);
|
||||
try renderOperandKind(writer, all_operand_kinds.values());
|
||||
try renderOpcodes(writer, a, registry.instructions, extended_structs);
|
||||
try renderOperandKinds(writer, a, all_operand_kinds.values(), extended_structs);
|
||||
try renderInstructionSet(writer, a, registry, extensions, all_operand_kinds);
|
||||
try renderOpcodes(writer, registry.instructions, extended_structs);
|
||||
try renderOperandKinds(writer, all_operand_kinds.values(), extended_structs);
|
||||
try renderInstructionSet(writer, registry, extensions, all_operand_kinds);
|
||||
}
|
||||
|
||||
fn renderInstructionSet(
|
||||
writer: anytype,
|
||||
a: Allocator,
|
||||
core: CoreRegistry,
|
||||
extensions: []const Extension,
|
||||
all_operand_kinds: OperandKindMap,
|
||||
) !void {
|
||||
_ = a;
|
||||
try writer.writeAll(
|
||||
\\pub const InstructionSet = enum {
|
||||
\\ core,
|
||||
);
|
||||
|
||||
for (extensions) |ext| {
|
||||
try writer.print("{p},\n", .{std.zig.fmtId(ext.name)});
|
||||
try writer.print("{f},\n", .{formatId(ext.name)});
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -340,14 +357,14 @@ fn renderInstructionsCase(
|
||||
// but there aren't so many total aliases and that would add more overhead in total. We will
|
||||
// just filter those out when needed.
|
||||
|
||||
try writer.print(".{p_} => &[_]Instruction{{\n", .{std.zig.fmtId(set_name)});
|
||||
try writer.print(".{f} => &.{{\n", .{formatId(set_name)});
|
||||
|
||||
for (instructions) |inst| {
|
||||
try writer.print(
|
||||
\\.{{
|
||||
\\ .name = "{s}",
|
||||
\\ .opcode = {},
|
||||
\\ .operands = &[_]Operand{{
|
||||
\\ .operands = &.{{
|
||||
\\
|
||||
, .{ inst.opname, inst.opcode });
|
||||
|
||||
@@ -362,7 +379,7 @@ fn renderInstructionsCase(
|
||||
|
||||
const kind = all_operand_kinds.get(.{ set_name, operand.kind }) orelse
|
||||
all_operand_kinds.get(.{ "core", operand.kind }).?;
|
||||
try writer.print(".{{.kind = .{p_}, .quantifier = .{s}}},\n", .{ std.zig.fmtId(kind.kind), quantifier });
|
||||
try writer.print(".{{.kind = .{f}, .quantifier = .{s}}},\n", .{ formatId(kind.kind), quantifier });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -378,54 +395,69 @@ fn renderInstructionsCase(
|
||||
);
|
||||
}
|
||||
|
||||
fn renderClass(writer: anytype, a: Allocator, instructions: []const Instruction) !void {
|
||||
var class_map = std.StringArrayHashMap(void).init(a);
|
||||
fn renderClass(writer: anytype, instructions: []const Instruction) !void {
|
||||
var class_map = std.StringArrayHashMap(void).init(allocator);
|
||||
|
||||
for (instructions) |inst| {
|
||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) {
|
||||
continue;
|
||||
}
|
||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) continue;
|
||||
try class_map.put(inst.class.?, {});
|
||||
}
|
||||
|
||||
try writer.writeAll("pub const Class = enum {\n");
|
||||
for (class_map.keys()) |class| {
|
||||
try renderInstructionClass(writer, class);
|
||||
try writer.writeAll(",\n");
|
||||
try writer.print("{f},\n", .{formatId(class)});
|
||||
}
|
||||
try writer.writeAll("};\n\n");
|
||||
}
|
||||
|
||||
fn renderInstructionClass(writer: anytype, class: []const u8) !void {
|
||||
// Just assume that these wont clobber zig builtin types.
|
||||
var prev_was_sep = true;
|
||||
for (class) |c| {
|
||||
switch (c) {
|
||||
'-', '_' => prev_was_sep = true,
|
||||
else => if (prev_was_sep) {
|
||||
try writer.writeByte(std.ascii.toUpper(c));
|
||||
prev_was_sep = false;
|
||||
} else {
|
||||
try writer.writeByte(std.ascii.toLower(c));
|
||||
},
|
||||
const Formatter = struct {
|
||||
data: []const u8,
|
||||
|
||||
fn format(f: Formatter, writer: *std.io.Writer) std.io.Writer.Error!void {
|
||||
var id_buf: [128]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&id_buf);
|
||||
const fw = fbs.writer();
|
||||
for (f.data, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'-', '_', '.', '~', ' ' => fw.writeByte('_') catch return error.WriteFailed,
|
||||
'a'...'z', '0'...'9' => fw.writeByte(c) catch return error.WriteFailed,
|
||||
'A'...'Z' => {
|
||||
if ((i > 0 and std.ascii.isLower(f.data[i - 1])) or
|
||||
(i > 0 and std.ascii.isUpper(f.data[i - 1]) and
|
||||
i + 1 < f.data.len and std.ascii.isLower(f.data[i + 1])))
|
||||
{
|
||||
_ = fw.write(&.{ '_', std.ascii.toLower(c) }) catch return error.WriteFailed;
|
||||
} else {
|
||||
fw.writeByte(std.ascii.toLower(c)) catch return error.WriteFailed;
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that this won't clobber with zig keywords
|
||||
try writer.print("{f}", .{std.zig.fmtId(fbs.getWritten())});
|
||||
}
|
||||
};
|
||||
|
||||
fn formatId(identifier: []const u8) std.fmt.Alt(Formatter, Formatter.format) {
|
||||
return .{ .data = .{ .data = identifier } };
|
||||
}
|
||||
|
||||
fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
||||
try writer.writeAll(
|
||||
\\pub const OperandKind = enum {
|
||||
\\ Opcode,
|
||||
\\ opcode,
|
||||
\\
|
||||
);
|
||||
for (operands) |operand| {
|
||||
try writer.print("{p},\n", .{std.zig.fmtId(operand.kind)});
|
||||
try writer.print("{f},\n", .{formatId(operand.kind)});
|
||||
}
|
||||
try writer.writeAll(
|
||||
\\
|
||||
\\pub fn category(self: OperandKind) OperandCategory {
|
||||
\\ return switch (self) {
|
||||
\\ .Opcode => .literal,
|
||||
\\ .opcode => .literal,
|
||||
\\
|
||||
);
|
||||
for (operands) |operand| {
|
||||
@@ -436,26 +468,26 @@ fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
||||
.Literal => "literal",
|
||||
.Composite => "composite",
|
||||
};
|
||||
try writer.print(".{p_} => .{s},\n", .{ std.zig.fmtId(operand.kind), cat });
|
||||
try writer.print(".{f} => .{s},\n", .{ formatId(operand.kind), cat });
|
||||
}
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\}
|
||||
\\pub fn enumerants(self: OperandKind) []const Enumerant {
|
||||
\\ return switch (self) {
|
||||
\\ .Opcode => unreachable,
|
||||
\\ .opcode => unreachable,
|
||||
\\
|
||||
);
|
||||
for (operands) |operand| {
|
||||
switch (operand.category) {
|
||||
.BitEnum, .ValueEnum => {},
|
||||
else => {
|
||||
try writer.print(".{p_} => unreachable,\n", .{std.zig.fmtId(operand.kind)});
|
||||
try writer.print(".{f} => unreachable,\n", .{formatId(operand.kind)});
|
||||
continue;
|
||||
},
|
||||
}
|
||||
|
||||
try writer.print(".{p_} => &[_]Enumerant{{", .{std.zig.fmtId(operand.kind)});
|
||||
try writer.print(".{f} => &.{{", .{formatId(operand.kind)});
|
||||
for (operand.enumerants.?) |enumerant| {
|
||||
if (enumerant.value == .bitflag and std.mem.eql(u8, enumerant.enumerant, "None")) {
|
||||
continue;
|
||||
@@ -474,32 +506,30 @@ fn renderEnumerant(writer: anytype, enumerant: Enumerant) !void {
|
||||
.bitflag => |flag| try writer.writeAll(flag),
|
||||
.int => |int| try writer.print("{}", .{int}),
|
||||
}
|
||||
try writer.writeAll(", .parameters = &[_]OperandKind{");
|
||||
try writer.writeAll(", .parameters = &.{");
|
||||
for (enumerant.parameters, 0..) |param, i| {
|
||||
if (i != 0)
|
||||
try writer.writeAll(", ");
|
||||
// Note, param.quantifier will always be one.
|
||||
try writer.print(".{p_}", .{std.zig.fmtId(param.kind)});
|
||||
try writer.print(".{f}", .{formatId(param.kind)});
|
||||
}
|
||||
try writer.writeAll("}}");
|
||||
}
|
||||
|
||||
fn renderOpcodes(
|
||||
writer: anytype,
|
||||
a: Allocator,
|
||||
instructions: []const Instruction,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
var inst_map = std.AutoArrayHashMap(u32, usize).init(a);
|
||||
var inst_map = std.AutoArrayHashMap(u32, usize).init(allocator);
|
||||
try inst_map.ensureTotalCapacity(instructions.len);
|
||||
|
||||
var aliases = std.ArrayList(struct { inst: usize, alias: usize }).init(a);
|
||||
var aliases = std.ArrayList(struct { inst: usize, alias: usize }).init(allocator);
|
||||
try aliases.ensureTotalCapacity(instructions.len);
|
||||
|
||||
for (instructions, 0..) |inst, i| {
|
||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) {
|
||||
continue;
|
||||
}
|
||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) continue;
|
||||
|
||||
const result = inst_map.getOrPutAssumeCapacity(inst.opcode);
|
||||
if (!result.found_existing) {
|
||||
result.value_ptr.* = i;
|
||||
@@ -525,7 +555,7 @@ fn renderOpcodes(
|
||||
try writer.writeAll("pub const Opcode = enum(u16) {\n");
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try writer.print("{p} = {},\n", .{ std.zig.fmtId(inst.opname), inst.opcode });
|
||||
try writer.print("{f} = {},\n", .{ std.zig.fmtId(inst.opname), inst.opcode });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -533,9 +563,9 @@ fn renderOpcodes(
|
||||
);
|
||||
|
||||
for (aliases.items) |alias| {
|
||||
try writer.print("pub const {} = Opcode.{p_};\n", .{
|
||||
std.zig.fmtId(instructions[alias.inst].opname),
|
||||
std.zig.fmtId(instructions[alias.alias].opname),
|
||||
try writer.print("pub const {f} = Opcode.{f};\n", .{
|
||||
formatId(instructions[alias.inst].opname),
|
||||
formatId(instructions[alias.alias].opname),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -548,7 +578,7 @@ fn renderOpcodes(
|
||||
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs);
|
||||
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs, false);
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -561,9 +591,7 @@ fn renderOpcodes(
|
||||
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try writer.print(".{p_} => .", .{std.zig.fmtId(inst.opname)});
|
||||
try renderInstructionClass(writer, inst.class.?);
|
||||
try writer.writeAll(",\n");
|
||||
try writer.print(".{f} => .{f},\n", .{ std.zig.fmtId(inst.opname), formatId(inst.class.?) });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@@ -576,14 +604,13 @@ fn renderOpcodes(
|
||||
|
||||
fn renderOperandKinds(
|
||||
writer: anytype,
|
||||
a: Allocator,
|
||||
kinds: []const OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
for (kinds) |kind| {
|
||||
switch (kind.category) {
|
||||
.ValueEnum => try renderValueEnum(writer, a, kind, extended_structs),
|
||||
.BitEnum => try renderBitEnum(writer, a, kind, extended_structs),
|
||||
.ValueEnum => try renderValueEnum(writer, kind, extended_structs),
|
||||
.BitEnum => try renderBitEnum(writer, kind, extended_structs),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@@ -591,20 +618,18 @@ fn renderOperandKinds(
|
||||
|
||||
fn renderValueEnum(
|
||||
writer: anytype,
|
||||
a: Allocator,
|
||||
enumeration: OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
||||
|
||||
var enum_map = std.AutoArrayHashMap(u32, usize).init(a);
|
||||
var enum_map = std.AutoArrayHashMap(u32, usize).init(allocator);
|
||||
try enum_map.ensureTotalCapacity(enumerants.len);
|
||||
|
||||
var aliases = std.ArrayList(struct { enumerant: usize, alias: usize }).init(a);
|
||||
var aliases = std.ArrayList(struct { enumerant: usize, alias: usize }).init(allocator);
|
||||
try aliases.ensureTotalCapacity(enumerants.len);
|
||||
|
||||
for (enumerants, 0..) |enumerant, i| {
|
||||
try writer.context.flush();
|
||||
const value: u31 = switch (enumerant.value) {
|
||||
.int => |value| value,
|
||||
// Some extensions declare ints as string
|
||||
@@ -632,25 +657,25 @@ fn renderValueEnum(
|
||||
|
||||
const enum_indices = enum_map.values();
|
||||
|
||||
try writer.print("pub const {} = enum(u32) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
try writer.print("pub const {f} = enum(u32) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
|
||||
for (enum_indices) |i| {
|
||||
const enumerant = enumerants[i];
|
||||
// if (enumerant.value != .int) return error.InvalidRegistry;
|
||||
|
||||
switch (enumerant.value) {
|
||||
.int => |value| try writer.print("{p} = {},\n", .{ std.zig.fmtId(enumerant.enumerant), value }),
|
||||
.bitflag => |value| try writer.print("{p} = {s},\n", .{ std.zig.fmtId(enumerant.enumerant), value }),
|
||||
.int => |value| try writer.print("{f} = {},\n", .{ formatId(enumerant.enumerant), value }),
|
||||
.bitflag => |value| try writer.print("{f} = {s},\n", .{ formatId(enumerant.enumerant), value }),
|
||||
}
|
||||
}
|
||||
|
||||
try writer.writeByte('\n');
|
||||
|
||||
for (aliases.items) |alias| {
|
||||
try writer.print("pub const {} = {}.{p_};\n", .{
|
||||
std.zig.fmtId(enumerants[alias.enumerant].enumerant),
|
||||
try writer.print("pub const {f} = {f}.{f};\n", .{
|
||||
formatId(enumerants[alias.enumerant].enumerant),
|
||||
std.zig.fmtId(enumeration.kind),
|
||||
std.zig.fmtId(enumerants[alias.alias].enumerant),
|
||||
formatId(enumerants[alias.alias].enumerant),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -659,11 +684,11 @@ fn renderValueEnum(
|
||||
return;
|
||||
}
|
||||
|
||||
try writer.print("\npub const Extended = union({}) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
try writer.print("\npub const Extended = union({f}) {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
|
||||
for (enum_indices) |i| {
|
||||
const enumerant = enumerants[i];
|
||||
try renderOperand(writer, .@"union", enumerant.enumerant, enumerant.parameters, extended_structs);
|
||||
try renderOperand(writer, .@"union", enumerant.enumerant, enumerant.parameters, extended_structs, true);
|
||||
}
|
||||
|
||||
try writer.writeAll("};\n};\n");
|
||||
@@ -671,16 +696,15 @@ fn renderValueEnum(
|
||||
|
||||
fn renderBitEnum(
|
||||
writer: anytype,
|
||||
a: Allocator,
|
||||
enumeration: OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
try writer.print("pub const {} = packed struct {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
try writer.print("pub const {f} = packed struct {{\n", .{std.zig.fmtId(enumeration.kind)});
|
||||
|
||||
var flags_by_bitpos = [_]?usize{null} ** 32;
|
||||
const enumerants = enumeration.enumerants orelse return error.InvalidRegistry;
|
||||
|
||||
var aliases = std.ArrayList(struct { flag: usize, alias: u5 }).init(a);
|
||||
var aliases = std.ArrayList(struct { flag: usize, alias: u5 }).init(allocator);
|
||||
try aliases.ensureTotalCapacity(enumerants.len);
|
||||
|
||||
for (enumerants, 0..) |enumerant, i| {
|
||||
@@ -715,7 +739,7 @@ fn renderBitEnum(
|
||||
|
||||
for (flags_by_bitpos, 0..) |maybe_flag_index, bitpos| {
|
||||
if (maybe_flag_index) |flag_index| {
|
||||
try writer.print("{p_}", .{std.zig.fmtId(enumerants[flag_index].enumerant)});
|
||||
try writer.print("{f}", .{formatId(enumerants[flag_index].enumerant)});
|
||||
} else {
|
||||
try writer.print("_reserved_bit_{}", .{bitpos});
|
||||
}
|
||||
@@ -726,10 +750,10 @@ fn renderBitEnum(
|
||||
try writer.writeByte('\n');
|
||||
|
||||
for (aliases.items) |alias| {
|
||||
try writer.print("pub const {}: {} = .{{.{p_} = true}};\n", .{
|
||||
std.zig.fmtId(enumerants[alias.flag].enumerant),
|
||||
try writer.print("pub const {f}: {f} = .{{.{f} = true}};\n", .{
|
||||
formatId(enumerants[alias.flag].enumerant),
|
||||
std.zig.fmtId(enumeration.kind),
|
||||
std.zig.fmtId(enumerants[flags_by_bitpos[alias.alias].?].enumerant),
|
||||
formatId(enumerants[flags_by_bitpos[alias.alias].?].enumerant),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -747,7 +771,7 @@ fn renderBitEnum(
|
||||
};
|
||||
const enumerant = enumerants[flag_index];
|
||||
|
||||
try renderOperand(writer, .mask, enumerant.enumerant, enumerant.parameters, extended_structs);
|
||||
try renderOperand(writer, .mask, enumerant.enumerant, enumerant.parameters, extended_structs, true);
|
||||
}
|
||||
|
||||
try writer.writeAll("};\n};\n");
|
||||
@@ -763,11 +787,18 @@ fn renderOperand(
|
||||
field_name: []const u8,
|
||||
parameters: []const Operand,
|
||||
extended_structs: ExtendedStructSet,
|
||||
snake_case: bool,
|
||||
) !void {
|
||||
if (kind == .instruction) {
|
||||
try writer.writeByte('.');
|
||||
}
|
||||
try writer.print("{}", .{std.zig.fmtId(field_name)});
|
||||
|
||||
if (snake_case) {
|
||||
try writer.print("{f}", .{formatId(field_name)});
|
||||
} else {
|
||||
try writer.print("{f}", .{std.zig.fmtId(field_name)});
|
||||
}
|
||||
|
||||
if (parameters.len == 0) {
|
||||
switch (kind) {
|
||||
.@"union" => try writer.writeAll(",\n"),
|
||||
@@ -787,7 +818,7 @@ fn renderOperand(
|
||||
try writer.writeByte('?');
|
||||
}
|
||||
|
||||
try writer.writeAll("struct{");
|
||||
try writer.writeAll("struct {");
|
||||
|
||||
for (parameters, 0..) |param, j| {
|
||||
if (j != 0) {
|
||||
@@ -804,7 +835,11 @@ fn renderOperand(
|
||||
}
|
||||
}
|
||||
|
||||
try writer.print("{}", .{std.zig.fmtId(param.kind)});
|
||||
if (std.mem.startsWith(u8, param.kind, "Id")) {
|
||||
_ = try writer.write("Id");
|
||||
} else {
|
||||
try writer.print("{f}", .{std.zig.fmtId(param.kind)});
|
||||
}
|
||||
|
||||
if (extended_structs.contains(param.kind)) {
|
||||
try writer.writeAll(".Extended");
|
||||
@@ -830,49 +865,24 @@ fn renderOperand(
|
||||
fn renderFieldName(writer: anytype, operands: []const Operand, field_index: usize) !void {
|
||||
const operand = operands[field_index];
|
||||
|
||||
// Should be enough for all names - adjust as needed.
|
||||
var name_backing_buffer: [64]u8 = undefined;
|
||||
var name_buffer = std.ArrayListUnmanaged(u8).initBuffer(&name_backing_buffer);
|
||||
|
||||
derive_from_kind: {
|
||||
// Operand names are often in the json encoded as "'Name'" (with two sets of quotes).
|
||||
// Additionally, some operands have ~ in them at the end (D~ref~).
|
||||
const name = std.mem.trim(u8, operand.name, "'~");
|
||||
if (name.len == 0) {
|
||||
break :derive_from_kind;
|
||||
}
|
||||
if (name.len == 0) break :derive_from_kind;
|
||||
|
||||
// Some names have weird characters in them (like newlines) - skip any such ones.
|
||||
// Use the same loop to transform to snake-case.
|
||||
for (name) |c| {
|
||||
switch (c) {
|
||||
'a'...'z', '0'...'9' => name_buffer.appendAssumeCapacity(c),
|
||||
'A'...'Z' => name_buffer.appendAssumeCapacity(std.ascii.toLower(c)),
|
||||
' ', '~' => name_buffer.appendAssumeCapacity('_'),
|
||||
'a'...'z', '0'...'9', 'A'...'Z', ' ', '~' => continue,
|
||||
else => break :derive_from_kind,
|
||||
}
|
||||
}
|
||||
|
||||
// Assume there are no duplicate 'name' fields.
|
||||
try writer.print("{p_}", .{std.zig.fmtId(name_buffer.items)});
|
||||
try writer.print("{f}", .{formatId(name)});
|
||||
return;
|
||||
}
|
||||
|
||||
// Translate to snake case.
|
||||
name_buffer.items.len = 0;
|
||||
for (operand.kind, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'a'...'z', '0'...'9' => name_buffer.appendAssumeCapacity(c),
|
||||
'A'...'Z' => if (i > 0 and std.ascii.isLower(operand.kind[i - 1])) {
|
||||
name_buffer.appendSliceAssumeCapacity(&[_]u8{ '_', std.ascii.toLower(c) });
|
||||
} else {
|
||||
name_buffer.appendAssumeCapacity(std.ascii.toLower(c));
|
||||
},
|
||||
else => unreachable, // Assume that the name is valid C-syntax (and contains no underscores).
|
||||
}
|
||||
}
|
||||
|
||||
try writer.print("{p_}", .{std.zig.fmtId(name_buffer.items)});
|
||||
try writer.print("{f}", .{formatId(operand.kind)});
|
||||
|
||||
// For fields derived from type name, there could be any amount.
|
||||
// Simply check against all other fields, and if another similar one exists, add a number.
|
||||
|
||||
@@ -37,9 +37,11 @@ pub const InstructionPrintingClass = struct {
|
||||
pub const Instruction = struct {
|
||||
opname: []const u8,
|
||||
class: ?[]const u8 = null, // Note: Only available in the core registry.
|
||||
aliases: [][]const u8 = &[_][]const u8{},
|
||||
opcode: u32,
|
||||
operands: []Operand = &[_]Operand{},
|
||||
capabilities: [][]const u8 = &[_][]const u8{},
|
||||
provisional: bool = false,
|
||||
// DebugModuleINTEL has this...
|
||||
capability: ?[]const u8 = null,
|
||||
extensions: [][]const u8 = &[_][]const u8{},
|
||||
@@ -81,6 +83,7 @@ pub const OperandKind = struct {
|
||||
|
||||
pub const Enumerant = struct {
|
||||
enumerant: []const u8,
|
||||
aliases: [][]const u8 = &[_][]const u8{},
|
||||
value: union(enum) {
|
||||
bitflag: []const u8, // Hexadecimal representation of the value
|
||||
int: u31,
|
||||
@@ -100,6 +103,7 @@ pub const Enumerant = struct {
|
||||
pub const jsonStringify = @compileError("not supported");
|
||||
},
|
||||
capabilities: [][]const u8 = &[_][]const u8{},
|
||||
provisional: bool = false,
|
||||
/// Valid for .ValueEnum and .BitEnum
|
||||
extensions: [][]const u8 = &[_][]const u8{},
|
||||
/// `quantifier` will always be `null`.
|
||||
|
||||
Reference in New Issue
Block a user