mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
spirv: define and use extended instruction set opcodes
This commit is contained in:
parent
246e1de554
commit
cd4b03c5ed
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -125,9 +125,9 @@ pub const Decl = struct {
|
||||
/// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
|
||||
result_id: Id,
|
||||
/// The offset of the first dependency of this decl in the `decl_deps` array.
|
||||
begin_dep: u32,
|
||||
begin_dep: usize = 0,
|
||||
/// The past-end offset of the dependencies of this decl in the `decl_deps` array.
|
||||
end_dep: u32,
|
||||
end_dep: usize = 0,
|
||||
};
|
||||
|
||||
/// This models a kernel entry point.
|
||||
@ -258,7 +258,6 @@ pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.In
|
||||
.generic => .invocation_global,
|
||||
else => .global,
|
||||
};
|
||||
|
||||
entry.value_ptr.* = try module.allocDecl(kind);
|
||||
}
|
||||
|
||||
@ -782,15 +781,15 @@ pub fn builtin(
|
||||
const gop = try module.cache.builtins.getOrPut(module.gpa, .{ spirv_builtin, storage_class });
|
||||
if (!gop.found_existing) {
|
||||
const decl_index = try module.allocDecl(.global);
|
||||
const result_id = module.declPtr(decl_index).result_id;
|
||||
const decl = module.declPtr(decl_index);
|
||||
|
||||
gop.value_ptr.* = decl_index;
|
||||
try module.sections.globals.emit(module.gpa, .OpVariable, .{
|
||||
.id_result_type = result_ty_id,
|
||||
.id_result = result_id,
|
||||
.id_result = decl.result_id,
|
||||
.storage_class = storage_class,
|
||||
});
|
||||
try module.decorate(result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
|
||||
try module.declareDeclDeps(decl_index, &.{});
|
||||
try module.decorate(decl.result_id, .{ .built_in = .{ .built_in = spirv_builtin } });
|
||||
}
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
@ -847,8 +846,6 @@ pub fn allocDecl(module: *Module, kind: Decl.Kind) !Decl.Index {
|
||||
try module.decls.append(module.gpa, .{
|
||||
.kind = kind,
|
||||
.result_id = module.allocId(),
|
||||
.begin_dep = undefined,
|
||||
.end_dep = undefined,
|
||||
});
|
||||
|
||||
return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(module.decls.items.len - 1))));
|
||||
@ -858,17 +855,6 @@ pub fn declPtr(module: *Module, index: Decl.Index) *Decl {
|
||||
return &module.decls.items[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
/// Declare ALL dependencies for a decl.
|
||||
pub fn declareDeclDeps(module: *Module, decl_index: Decl.Index, deps: []const Decl.Index) !void {
|
||||
const begin_dep: u32 = @intCast(module.decl_deps.items.len);
|
||||
try module.decl_deps.appendSlice(module.gpa, deps);
|
||||
const end_dep: u32 = @intCast(module.decl_deps.items.len);
|
||||
|
||||
const decl = module.declPtr(decl_index);
|
||||
decl.begin_dep = begin_dep;
|
||||
decl.end_dep = end_dep;
|
||||
}
|
||||
|
||||
/// Declare a SPIR-V function as an entry point. This causes an extra wrapper
|
||||
/// function to be generated, which is then exported as the real entry point. The purpose of this
|
||||
/// wrapper is to allocate and initialize the structure holding the instance globals.
|
||||
|
||||
@ -21,7 +21,7 @@ pub fn deinit(section: *Section, allocator: Allocator) void {
|
||||
}
|
||||
|
||||
pub fn reset(section: *Section) void {
|
||||
section.instructions.items.len = 0;
|
||||
section.instructions.clearRetainingCapacity();
|
||||
}
|
||||
|
||||
pub fn toWords(section: Section) []Word {
|
||||
@ -86,16 +86,6 @@ pub fn emit(
|
||||
section.writeOperands(opcode.Operands(), operands);
|
||||
}
|
||||
|
||||
pub fn emitBranch(
|
||||
section: *Section,
|
||||
allocator: Allocator,
|
||||
target_label: spec.Id,
|
||||
) !void {
|
||||
try section.emit(allocator, .OpBranch, .{
|
||||
.target_label = target_label,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn writeWord(section: *Section, word: Word) void {
|
||||
section.instructions.appendAssumeCapacity(word);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@ const Linker = @This();
|
||||
|
||||
base: link.File,
|
||||
module: Module,
|
||||
cg: CodeGen,
|
||||
|
||||
pub fn createEmpty(
|
||||
arena: Allocator,
|
||||
@ -63,6 +64,16 @@ pub fn createEmpty(
|
||||
.arena = arena,
|
||||
.zcu = comp.zcu.?,
|
||||
},
|
||||
.cg = .{
|
||||
// These fields are populated in generate()
|
||||
.pt = undefined,
|
||||
.air = undefined,
|
||||
.liveness = undefined,
|
||||
.owner_nav = undefined,
|
||||
.module = undefined,
|
||||
.control_flow = .{ .structured = .{} },
|
||||
.base_line = undefined,
|
||||
},
|
||||
};
|
||||
errdefer linker.deinit();
|
||||
|
||||
@ -84,6 +95,7 @@ pub fn open(
|
||||
}
|
||||
|
||||
pub fn deinit(linker: *Linker) void {
|
||||
linker.cg.deinit();
|
||||
linker.module.deinit();
|
||||
}
|
||||
|
||||
@ -99,29 +111,41 @@ fn generate(
|
||||
const gpa = zcu.gpa;
|
||||
const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg;
|
||||
|
||||
var cg: CodeGen = .{
|
||||
linker.cg.control_flow.deinit(gpa);
|
||||
linker.cg.args.clearRetainingCapacity();
|
||||
linker.cg.inst_results.clearRetainingCapacity();
|
||||
linker.cg.id_scratch.clearRetainingCapacity();
|
||||
linker.cg.prologue.reset();
|
||||
linker.cg.body.reset();
|
||||
|
||||
linker.cg = .{
|
||||
.pt = pt,
|
||||
.module = &linker.module,
|
||||
.owner_nav = nav_index,
|
||||
.air = air,
|
||||
.liveness = liveness,
|
||||
.owner_nav = nav_index,
|
||||
.module = &linker.module,
|
||||
.control_flow = switch (structured_cfg) {
|
||||
true => .{ .structured = .{} },
|
||||
false => .{ .unstructured = .{} },
|
||||
},
|
||||
.base_line = zcu.navSrcLine(nav_index),
|
||||
};
|
||||
defer cg.deinit();
|
||||
|
||||
cg.genNav(do_codegen) catch |err| switch (err) {
|
||||
error.CodegenFail => switch (zcu.codegenFailMsg(nav_index, cg.error_msg.?)) {
|
||||
.args = linker.cg.args,
|
||||
.inst_results = linker.cg.inst_results,
|
||||
.id_scratch = linker.cg.id_scratch,
|
||||
.prologue = linker.cg.prologue,
|
||||
.body = linker.cg.body,
|
||||
};
|
||||
|
||||
linker.cg.genNav(do_codegen) catch |err| switch (err) {
|
||||
error.CodegenFail => switch (zcu.codegenFailMsg(nav_index, linker.cg.error_msg.?)) {
|
||||
error.CodegenFail => {},
|
||||
error.OutOfMemory => |e| return e,
|
||||
},
|
||||
else => |other| {
|
||||
// There might be an error that happened *after* linker.error_msg
|
||||
// was already allocated, so be sure to free it.
|
||||
if (cg.error_msg) |error_msg| {
|
||||
if (linker.cg.error_msg) |error_msg| {
|
||||
error_msg.deinit(gpa);
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ const ExtendedStructSet = std.StringHashMap(void);
|
||||
|
||||
const Extension = struct {
|
||||
name: []const u8,
|
||||
opcode_name: []const u8,
|
||||
spec: ExtensionRegistry,
|
||||
};
|
||||
|
||||
@ -44,23 +45,11 @@ const OperandKindMap = std.ArrayHashMap(StringPair, OperandKind, StringPairConte
|
||||
|
||||
/// Khronos made it so that these names are not defined explicitly, so
|
||||
/// we need to hardcode it (like they did).
|
||||
/// See https://github.com/KhronosGroup/SPIRV-Registry/
|
||||
const set_names = std.StaticStringMap([]const u8).initComptime(.{
|
||||
.{ "opencl.std.100", "OpenCL.std" },
|
||||
.{ "glsl.std.450", "GLSL.std.450" },
|
||||
.{ "opencl.debuginfo.100", "OpenCL.DebugInfo.100" },
|
||||
.{ "spv-amd-shader-ballot", "SPV_AMD_shader_ballot" },
|
||||
.{ "nonsemantic.shader.debuginfo.100", "NonSemantic.Shader.DebugInfo.100" },
|
||||
.{ "nonsemantic.vkspreflection", "NonSemantic.VkspReflection" },
|
||||
.{ "nonsemantic.clspvreflection", "NonSemantic.ClspvReflection.6" }, // This version needs to be handled manually
|
||||
.{ "spv-amd-gcn-shader", "SPV_AMD_gcn_shader" },
|
||||
.{ "spv-amd-shader-trinary-minmax", "SPV_AMD_shader_trinary_minmax" },
|
||||
.{ "debuginfo", "DebugInfo" },
|
||||
.{ "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" },
|
||||
/// See https://github.com/KhronosGroup/SPIRV-Registry
|
||||
const set_names = std.StaticStringMap(struct { []const u8, []const u8 }).initComptime(.{
|
||||
.{ "opencl.std.100", .{ "OpenCL.std", "OpenClOpcode" } },
|
||||
.{ "glsl.std.450", .{ "GLSL.std.450", "GlslOpcode" } },
|
||||
.{ "zig", .{ "zig", "Zig" } },
|
||||
});
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.smp_allocator);
|
||||
@ -78,7 +67,7 @@ pub fn main() !void {
|
||||
const dir = try std.fs.cwd().openDir(json_path, .{ .iterate = true });
|
||||
|
||||
const core_spec = try readRegistry(CoreRegistry, dir, "spirv.core.grammar.json");
|
||||
std.sort.block(Instruction, core_spec.instructions, CmpInst{}, CmpInst.lt);
|
||||
std.mem.sortUnstable(Instruction, core_spec.instructions, CmpInst{}, CmpInst.lt);
|
||||
|
||||
var exts = std.ArrayList(Extension).init(allocator);
|
||||
|
||||
@ -134,14 +123,24 @@ fn readExtRegistry(exts: *std.ArrayList(Extension), dir: std.fs.Dir, sub_path: [
|
||||
const name = filename["extinst.".len .. filename.len - ".grammar.json".len];
|
||||
const spec = try readRegistry(ExtensionRegistry, dir, sub_path);
|
||||
|
||||
const set_name = set_names.get(name) orelse {
|
||||
std.log.info("ignored instruction set '{s}'", .{name});
|
||||
return;
|
||||
};
|
||||
|
||||
std.sort.block(Instruction, spec.instructions, CmpInst{}, CmpInst.lt);
|
||||
|
||||
try exts.append(.{ .name = set_names.get(name).?, .spec = spec });
|
||||
try exts.append(.{
|
||||
.name = set_name.@"0",
|
||||
.opcode_name = set_name.@"1",
|
||||
.spec = spec,
|
||||
});
|
||||
}
|
||||
|
||||
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.
|
||||
// TODO: ALI
|
||||
@setEvalBranchQuota(10000);
|
||||
|
||||
var scanner = std.json.Scanner.initCompleteInput(allocator, spec);
|
||||
@ -191,7 +190,11 @@ fn tagPriorityScore(tag: []const u8) usize {
|
||||
}
|
||||
}
|
||||
|
||||
fn render(writer: *std.io.Writer, 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.
|
||||
\\
|
||||
@ -317,13 +320,18 @@ fn render(writer: *std.io.Writer, registry: CoreRegistry, extensions: []const Ex
|
||||
// Note: extensions don't seem to have class.
|
||||
try renderClass(writer, registry.instructions);
|
||||
try renderOperandKind(writer, all_operand_kinds.values());
|
||||
try renderOpcodes(writer, registry.instructions, extended_structs);
|
||||
|
||||
try renderOpcodes(writer, "Opcode", true, registry.instructions, extended_structs);
|
||||
for (extensions) |ext| {
|
||||
try renderOpcodes(writer, ext.opcode_name, false, ext.spec.instructions, extended_structs);
|
||||
}
|
||||
|
||||
try renderOperandKinds(writer, all_operand_kinds.values(), extended_structs);
|
||||
try renderInstructionSet(writer, registry, extensions, all_operand_kinds);
|
||||
}
|
||||
|
||||
fn renderInstructionSet(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
core: CoreRegistry,
|
||||
extensions: []const Extension,
|
||||
all_operand_kinds: OperandKindMap,
|
||||
@ -358,7 +366,7 @@ fn renderInstructionSet(
|
||||
}
|
||||
|
||||
fn renderInstructionsCase(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
set_name: []const u8,
|
||||
instructions: []const Instruction,
|
||||
all_operand_kinds: OperandKindMap,
|
||||
@ -405,7 +413,7 @@ fn renderInstructionsCase(
|
||||
);
|
||||
}
|
||||
|
||||
fn renderClass(writer: anytype, instructions: []const Instruction) !void {
|
||||
fn renderClass(writer: *std.io.Writer, instructions: []const Instruction) !void {
|
||||
var class_map = std.StringArrayHashMap(void).init(allocator);
|
||||
|
||||
for (instructions) |inst| {
|
||||
@ -454,7 +462,7 @@ fn formatId(identifier: []const u8) std.fmt.Alt(Formatter, Formatter.format) {
|
||||
return .{ .data = .{ .data = identifier } };
|
||||
}
|
||||
|
||||
fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
||||
fn renderOperandKind(writer: *std.io.Writer, operands: []const OperandKind) !void {
|
||||
try writer.writeAll(
|
||||
\\pub const OperandKind = enum {
|
||||
\\ opcode,
|
||||
@ -510,7 +518,7 @@ fn renderOperandKind(writer: anytype, operands: []const OperandKind) !void {
|
||||
try writer.writeAll("};\n}\n};\n");
|
||||
}
|
||||
|
||||
fn renderEnumerant(writer: anytype, enumerant: Enumerant) !void {
|
||||
fn renderEnumerant(writer: *std.io.Writer, enumerant: Enumerant) !void {
|
||||
try writer.print(".{{.name = \"{s}\", .value = ", .{enumerant.enumerant});
|
||||
switch (enumerant.value) {
|
||||
.bitflag => |flag| try writer.writeAll(flag),
|
||||
@ -527,7 +535,9 @@ fn renderEnumerant(writer: anytype, enumerant: Enumerant) !void {
|
||||
}
|
||||
|
||||
fn renderOpcodes(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
opcode_type_name: []const u8,
|
||||
want_operands: bool,
|
||||
instructions: []const Instruction,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
@ -538,7 +548,9 @@ fn renderOpcodes(
|
||||
try aliases.ensureTotalCapacity(instructions.len);
|
||||
|
||||
for (instructions, 0..) |inst, i| {
|
||||
if (std.mem.eql(u8, inst.class.?, "@exclude")) continue;
|
||||
if (inst.class) |class| {
|
||||
if (std.mem.eql(u8, class, "@exclude")) continue;
|
||||
}
|
||||
|
||||
const result = inst_map.getOrPutAssumeCapacity(inst.opcode);
|
||||
if (!result.found_existing) {
|
||||
@ -562,58 +574,67 @@ fn renderOpcodes(
|
||||
|
||||
const instructions_indices = inst_map.values();
|
||||
|
||||
try writer.writeAll("pub const Opcode = enum(u16) {\n");
|
||||
try writer.print("\npub const {f} = enum(u16) {{\n", .{std.zig.fmtId(opcode_type_name)});
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try writer.print("{f} = {},\n", .{ std.zig.fmtId(inst.opname), inst.opcode });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\
|
||||
);
|
||||
try writer.writeAll("\n");
|
||||
|
||||
for (aliases.items) |alias| {
|
||||
try writer.print("pub const {f} = Opcode.{f};\n", .{
|
||||
try writer.print("pub const {f} = {f}.{f};\n", .{
|
||||
formatId(instructions[alias.inst].opname),
|
||||
std.zig.fmtId(opcode_type_name),
|
||||
formatId(instructions[alias.alias].opname),
|
||||
});
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\
|
||||
\\pub fn Operands(comptime self: Opcode) type {
|
||||
\\ return switch (self) {
|
||||
\\
|
||||
);
|
||||
if (want_operands) {
|
||||
try writer.print(
|
||||
\\
|
||||
\\pub fn Operands(comptime self: {f}) type {{
|
||||
\\ return switch (self) {{
|
||||
\\
|
||||
, .{std.zig.fmtId(opcode_type_name)});
|
||||
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs, false);
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try renderOperand(writer, .instruction, inst.opname, inst.operands, extended_structs, false);
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
|
||||
try writer.print(
|
||||
\\pub fn class(self: {f}) Class {{
|
||||
\\ return switch (self) {{
|
||||
\\
|
||||
, .{std.zig.fmtId(opcode_type_name)});
|
||||
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try writer.print(".{f} => .{f},\n", .{ std.zig.fmtId(inst.opname), formatId(inst.class.?) });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\}
|
||||
\\pub fn class(self: Opcode) Class {
|
||||
\\ return switch (self) {
|
||||
\\
|
||||
);
|
||||
|
||||
for (instructions_indices) |i| {
|
||||
const inst = instructions[i];
|
||||
try writer.print(".{f} => .{f},\n", .{ std.zig.fmtId(inst.opname), formatId(inst.class.?) });
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
\\ };
|
||||
\\}
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
fn renderOperandKinds(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
kinds: []const OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
@ -627,7 +648,7 @@ fn renderOperandKinds(
|
||||
}
|
||||
|
||||
fn renderValueEnum(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
enumeration: OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
@ -705,7 +726,7 @@ fn renderValueEnum(
|
||||
}
|
||||
|
||||
fn renderBitEnum(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
enumeration: OperandKind,
|
||||
extended_structs: ExtendedStructSet,
|
||||
) !void {
|
||||
@ -788,7 +809,7 @@ fn renderBitEnum(
|
||||
}
|
||||
|
||||
fn renderOperand(
|
||||
writer: anytype,
|
||||
writer: *std.io.Writer,
|
||||
kind: enum {
|
||||
@"union",
|
||||
instruction,
|
||||
@ -872,7 +893,7 @@ fn renderOperand(
|
||||
try writer.writeAll(",\n");
|
||||
}
|
||||
|
||||
fn renderFieldName(writer: anytype, operands: []const Operand, field_index: usize) !void {
|
||||
fn renderFieldName(writer: *std.io.Writer, operands: []const Operand, field_index: usize) !void {
|
||||
const operand = operands[field_index];
|
||||
|
||||
derive_from_kind: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user