aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2022-01-30 20:48:16 +0100
committerRobin Voetter <robin@voetter.nl>2022-11-23 19:17:58 +0100
commit074ba69ba6c730e1095bdf78bdcc31bb37c358b1 (patch)
treecb8bcc25858aa976bd21bd82ed9bce8b8d3c50ca /tools
parent32ce2f91a92c23d46c6836a6dd68ae0f08bb04c5 (diff)
downloadzig-074ba69ba6c730e1095bdf78bdcc31bb37c358b1.tar.gz
zig-074ba69ba6c730e1095bdf78bdcc31bb37c358b1.zip
spirv: assembler
spirv: introduce SpvModule.Fn to generate function code into spirv: assembler error message setup spirv: runtime spec info spirv: inline assembly tokenizer spirv: inline assembly lhs result/opcode parsing spirv: forgot to fmt spirv: tokenize opcodes and assigned result-ids spirv: operand parsing setup spirv: assembler string literals spirv: assembler integer literals spirv: assembler value enums spirv: assembler bit masks spirv: update assembler to new asm air format spirv: target 1.5 for now Current vulkan sdk version (1.3.204) ships spirv tools targetting 1.5, and so these do not work with binaries targetting 1.6 yet. In the future, this version number should be decided by the target. spirv: store operands in flat arraylist. Instead of having dedicated Operand variants for variadic operands, just flatten them and store them in the normal inst.operands list. This is a little simpler, but is not easily decodable in the operand data representation. spirv: parse variadic assembly operands spirv: improve assembler result-id tokenization spirv: begin instruction processing spirv: only remove decl if it was actually allocated spirv: work around weird miscompilation Seems like there are problems with switch in anonymous struct literals. spirv: begin resolving some types in assembler spirv: improve instruction processing spirv: rename some types + process OpTypeInt spirv: process OpTypeVector spirv: process OpTypeMatrix and OpTypeSampler spirv: add opcode class to spec, remove @exclude'd instructions spirv: process more type instructions spirv: OpTypeFunction spirv: OpTypeOpaque spirv: parse LiteralContextDependentNumber operands spirv: emit assembly instruction into right section spirv: parse OpPhi parameters spirv: inline assembly inputs spirv: also copy air types spirv: inline assembly outputs spirv: spir-v address spaces spirv: basic vector constants/types and shuffle spirv: assembler OpTypeImage spirv: some stuff spirv: remove spirv address spaces for now
Diffstat (limited to 'tools')
-rw-r--r--tools/gen_spirv_spec.zig175
1 files changed, 174 insertions, 1 deletions
diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig
index 619143d883..426276122c 100644
--- a/tools/gen_spirv_spec.zig
+++ b/tools/gen_spirv_spec.zig
@@ -116,6 +116,31 @@ fn render(writer: anytype, allocator: Allocator, registry: g.CoreRegistry) !void
\\pub const PairIdRefLiteralInteger = struct { target: IdRef, member: LiteralInteger };
\\pub const PairIdRefIdRef = [2]IdRef;
\\
+ \\pub const Quantifier = enum {
+ \\ required,
+ \\ optional,
+ \\ variadic,
+ \\};
+ \\
+ \\pub const Operand = struct {
+ \\ kind: OperandKind,
+ \\ quantifier: Quantifier,
+ \\};
+ \\
+ \\pub const OperandCategory = enum {
+ \\ bit_enum,
+ \\ value_enum,
+ \\ id,
+ \\ literal,
+ \\ composite,
+ \\};
+ \\
+ \\pub const Enumerant = struct {
+ \\ name: []const u8,
+ \\ value: Word,
+ \\ parameters: []const OperandKind,
+ \\};
+ \\
\\
);
@@ -123,14 +148,118 @@ fn render(writer: anytype, allocator: Allocator, registry: g.CoreRegistry) !void
\\pub const version = Version{{ .major = {}, .minor = {}, .patch = {} }};
\\pub const magic_number: Word = {s};
\\
+ \\
,
.{ registry.major_version, registry.minor_version, registry.revision, registry.magic_number },
);
+
const extended_structs = try extendedStructs(allocator, registry.operand_kinds);
+ try renderClass(writer, allocator, registry.instructions);
+ try renderOperandKind(writer, registry.operand_kinds);
try renderOpcodes(writer, allocator, registry.instructions, extended_structs);
try renderOperandKinds(writer, allocator, registry.operand_kinds, extended_structs);
}
+fn renderClass(writer: anytype, allocator: Allocator, instructions: []const g.Instruction) !void {
+ var class_map = std.StringArrayHashMap(void).init(allocator);
+
+ for (instructions) |inst| {
+ 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.writeAll("};\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));
+ },
+ }
+ }
+}
+
+fn renderOperandKind(writer: anytype, operands: []const g.OperandKind) !void {
+ try writer.writeAll("pub const OperandKind = enum {\n");
+ for (operands) |operand| {
+ try writer.print("{},\n", .{std.zig.fmtId(operand.kind)});
+ }
+ try writer.writeAll(
+ \\
+ \\pub fn category(self: OperandKind) OperandCategory {
+ \\return switch (self) {
+ \\
+ );
+ for (operands) |operand| {
+ const cat = switch (operand.category) {
+ .BitEnum => "bit_enum",
+ .ValueEnum => "value_enum",
+ .Id => "id",
+ .Literal => "literal",
+ .Composite => "composite",
+ };
+ try writer.print(".{} => .{s},\n", .{ std.zig.fmtId(operand.kind), cat });
+ }
+ try writer.writeAll(
+ \\};
+ \\}
+ \\pub fn enumerants(self: OperandKind) []const Enumerant {
+ \\return switch (self) {
+ \\
+ );
+ for (operands) |operand| {
+ switch (operand.category) {
+ .BitEnum, .ValueEnum => {},
+ else => {
+ try writer.print(".{} => unreachable,\n", .{std.zig.fmtId(operand.kind)});
+ continue;
+ },
+ }
+
+ try writer.print(".{} => &[_]Enumerant{{", .{std.zig.fmtId(operand.kind)});
+ for (operand.enumerants.?) |enumerant| {
+ if (enumerant.value == .bitflag and std.mem.eql(u8, enumerant.enumerant, "None")) {
+ continue;
+ }
+ try renderEnumerant(writer, enumerant);
+ try writer.writeAll(",");
+ }
+ try writer.writeAll("},\n");
+ }
+ try writer.writeAll("};\n}\n};\n");
+}
+
+fn renderEnumerant(writer: anytype, enumerant: g.Enumerant) !void {
+ try writer.print(".{{.name = \"{s}\", .value = ", .{enumerant.enumerant});
+ switch (enumerant.value) {
+ .bitflag => |flag| try writer.writeAll(flag),
+ .int => |int| try writer.print("{}", .{int}),
+ }
+ try writer.writeAll(", .parameters = &[_]OperandKind{");
+ for (enumerant.parameters) |param, i| {
+ if (i != 0)
+ try writer.writeAll(", ");
+ // Note, param.quantifier will always be one.
+ try writer.print(".{}", .{std.zig.fmtId(param.kind)});
+ }
+ try writer.writeAll("}}");
+}
+
fn renderOpcodes(
writer: anytype,
allocator: Allocator,
@@ -144,6 +273,9 @@ fn renderOpcodes(
try aliases.ensureTotalCapacity(instructions.len);
for (instructions) |inst, i| {
+ if (std.mem.eql(u8, inst.class.?, "@exclude")) {
+ continue;
+ }
const result = inst_map.getOrPutAssumeCapacity(inst.opcode);
if (!result.found_existing) {
result.value_ptr.* = i;
@@ -192,6 +324,47 @@ fn renderOpcodes(
const inst = instructions[i];
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs);
}
+
+ try writer.writeAll(
+ \\};
+ \\}
+ \\pub fn operands(self: Opcode) []const Operand {
+ \\return switch (self) {
+ \\
+ );
+
+ for (instructions_indices) |i| {
+ const inst = instructions[i];
+ try writer.print(".{} => &[_]Operand{{", .{std.zig.fmtId(inst.opname)});
+ for (inst.operands) |operand| {
+ const quantifier = if (operand.quantifier) |q|
+ switch (q) {
+ .@"?" => "optional",
+ .@"*" => "variadic",
+ }
+ else
+ "required";
+
+ try writer.print(".{{.kind = .{s}, .quantifier = .{s}}},", .{ operand.kind, quantifier });
+ }
+ try writer.writeAll("},\n");
+ }
+
+ try writer.writeAll(
+ \\};
+ \\}
+ \\pub fn class(self: Opcode) Class {
+ \\return switch (self) {
+ \\
+ );
+
+ for (instructions_indices) |i| {
+ const inst = instructions[i];
+ try writer.print(".{} => .", .{std.zig.fmtId(inst.opname)});
+ try renderInstructionClass(writer, inst.class.?);
+ try writer.writeAll(",\n");
+ }
+
try writer.writeAll("};\n}\n};\n");
}
@@ -298,7 +471,7 @@ fn renderBitEnum(
for (enumerants) |enumerant, i| {
if (enumerant.value != .bitflag) return error.InvalidRegistry;
const value = try parseHexInt(enumerant.value.bitflag);
- if (@popCount(value) == 0) {
+ if (value == 0) {
continue; // Skip 'none' items
}